Merge pull request #49 from jellyfin/release-10.1.0

Release 10.1.0
This commit is contained in:
Joshua M. Boniface
2019-01-22 13:05:08 -05:00
committed by GitHub
331 changed files with 49509 additions and 26112 deletions
+1
View File
@@ -0,0 +1 @@
/CONTRIBUTORS.md merge=union
+6
View File
@@ -9,8 +9,14 @@
- [bfayers](https://github.com/bfayers)
- [Bond_009](https://github.com/Bond-009)
- [AnthonyLavado](https://github.com/anthonylavado)
- [dkanada](https://github.com/dkanada)
- [sparky8251](https://github.com/sparky8251)
- [LeoVerto](https://github.com/LeoVerto)
- [cvium](https://github.com/cvium)
- [grafixeyehero](https://github.com/grafixeyehero)
- [Drago96](https://github.com/drago-96)
- [ViXXoR](https://github.com/ViXXoR)
- [nkmerrill] (https://github.com/nkmerrill)
# Emby Contributors
-38
View File
@@ -35,44 +35,6 @@
</p>
<p id="nonServerMsg"></p>
</form>
<div class="premiumPackage" style="display: none; margin-top: 1.5em;">
<div>
<form name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post">
<p id="regStatus">
</p>
<div class="supporterDescription">
<p>${MessagePluginRequiresSubscription}</p>
<p><a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">${LinkLearnMoreAboutSubscription}</a></p>
</div>
<div class="premiumDescription">
<p>${MessagePremiumPluginRequiresMembership}</p>
<p><a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">${LinkLearnMoreAboutSubscription}</a></p>
</div>
<div class="premiumHasPrice" style="display: none">
<p id="regPrice">
</p>
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" id="payPalEmail" name="business" value="mb_1358534950_biz@reedsplace.com">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" id="featureName" name="item_name" value="">
<input type="hidden" id="amount" name="amount" value="10">
<input type="hidden" id="featureId" name="item_number" value="">
<input type="hidden" name="notify_url" value="https://mb3admin.local/admin/service/services/ppipn.php">
<input type="hidden" name="return" id="paypalReturnUrl" value="#">
<button is="emby-button" type="submit" id="ppButton" class="raised block button-submit" style="background-color: #179BD7;color:#fff;">
<span>${RegisterWithPayPal}</span>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<br />
+22
View File
@@ -0,0 +1,22 @@
<div data-role="page" class="page standalonePage">
<div class="padded-left padded-right padded-bottom-page">
<form class="manualServerForm" style="margin: 0 auto;">
<h1 style="text-align: left;">${HeaderConnectToServer}</h1>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtServerHost" required="required" label="${LabelServerHost}" />
<div class="fieldDescription" style="text-align: left;">${LabelServerHostHelp}</div>
</div>
<br />
<div class="inputContainer">
<input is="emby-input" type="number" id="txtServerPort" step="1" min="0" value="8096" label="${LabelServerPort}" />
</div>
<br />
<button is="emby-button" type="submit" class="raised button-submit block">
<span>${ButtonConnect}</span>
</button>
<button is="emby-button" type="button" class="raised button-cancel block btnCancelManualServer">
<span>${ButtonCancel}</span>
</button>
</form>
</div>
</div>
+4 -43
View File
@@ -1,4 +1,4 @@
define(["events", "appStorage", "wakeOnLan"], function(events, appStorage, wakeOnLan) {
define(["events", "appStorage"], function(events, appStorage) {
"use strict";
function redetectBitrate(instance) {
@@ -201,36 +201,6 @@ define(["events", "appStorage", "wakeOnLan"], function(events, appStorage, wakeO
ratio && (options.minScale && (ratio = Math.max(options.minScale, ratio)), options.width && (options.width = Math.round(options.width * ratio)), options.height && (options.height = Math.round(options.height * ratio)), options.maxWidth && (options.maxWidth = Math.round(options.maxWidth * ratio)), options.maxHeight && (options.maxHeight = Math.round(options.maxHeight * ratio))), options.quality = options.quality || instance.getDefaultImageQuality(options.type), instance.normalizeImageOptions && instance.normalizeImageOptions(options)
}
function getCachedWakeOnLanInfo(instance) {
var serverId = instance.serverId(),
json = appStorage.getItem("server-" + serverId + "-wakeonlaninfo");
return json ? JSON.parse(json) : []
}
function refreshWakeOnLanInfoIfNeeded(instance) {
wakeOnLan.isSupported() && instance.accessToken() && !1 !== instance.enableAutomaticBitrateDetection && (console.log("refreshWakeOnLanInfoIfNeeded"), setTimeout(refreshWakeOnLanInfo.bind(instance), 1e4))
}
function refreshWakeOnLanInfo() {
var instance = this;
console.log("refreshWakeOnLanInfo"), instance.getWakeOnLanInfo().then(function(info) {
var serverId = instance.serverId();
return appStorage.setItem("server-" + serverId + "-wakeonlaninfo", JSON.stringify(info)), info
}, function(err) {
return []
})
}
function sendNextWakeOnLan(infos, index, resolve) {
if (index >= infos.length) return void resolve();
var info = infos[index];
console.log("sending wakeonlan to " + info.MacAddress), wakeOnLan.send(info).then(function(result) {
sendNextWakeOnLan(infos, index + 1, resolve)
}, function() {
sendNextWakeOnLan(infos, index + 1, resolve)
})
}
function compareVersions(a, b) {
a = a.split("."), b = b.split(".");
for (var i = 0, length = Math.max(a.length, b.length); i < length; i++) {
@@ -266,7 +236,7 @@ define(["events", "appStorage", "wakeOnLan"], function(events, appStorage, wakeO
}
return this._serverAddress
}, ApiClient.prototype.onNetworkChange = function() {
this.lastDetectedBitrate = 0, this.lastDetectedBitrateTime = 0, setSavedEndpointInfo(this, null), redetectBitrate(this), refreshWakeOnLanInfoIfNeeded(this)
this.lastDetectedBitrate = 0, this.lastDetectedBitrateTime = 0, setSavedEndpointInfo(this, null), redetectBitrate(this)
}, ApiClient.prototype.getUrl = function(name, params, serverAddress) {
if (!name) throw new Error("Url name cannot be empty");
var url = serverAddress || this._serverAddress;
@@ -301,7 +271,7 @@ define(["events", "appStorage", "wakeOnLan"], function(events, appStorage, wakeO
}
return this.fetchWithFailover(request, !0)
}, ApiClient.prototype.setAuthenticationInfo = function(accessKey, userId) {
this._currentUser = null, this._serverInfo.AccessToken = accessKey, this._serverInfo.UserId = userId, redetectBitrate(this), refreshWakeOnLanInfoIfNeeded(this)
this._currentUser = null, this._serverInfo.AccessToken = accessKey, this._serverInfo.UserId = userId, redetectBitrate(this)
}, ApiClient.prototype.serverInfo = function(info) {
return info && (this._serverInfo = info), this._serverInfo
}, ApiClient.prototype.getCurrentUserId = function() {
@@ -360,7 +330,7 @@ define(["events", "appStorage", "wakeOnLan"], function(events, appStorage, wakeO
contentType: "application/json"
}).then(function(result) {
var afterOnAuthenticated = function() {
redetectBitrate(instance), refreshWakeOnLanInfoIfNeeded(instance), resolve(result)
redetectBitrate(instance), resolve(result)
};
instance.onAuthenticated ? instance.onAuthenticated(instance, result).then(afterOnAuthenticated) : afterOnAuthenticated()
}, reject)
@@ -1579,19 +1549,10 @@ define(["events", "appStorage", "wakeOnLan"], function(events, appStorage, wakeO
return this.getJSON(this.getUrl("System/Endpoint")).then(function(endPointInfo) {
return setSavedEndpointInfo(instance, endPointInfo), endPointInfo
})
}, ApiClient.prototype.getWakeOnLanInfo = function() {
return this.getJSON(this.getUrl("System/WakeOnLanInfo"))
}, ApiClient.prototype.getLatestItems = function(options) {
return options = options || {}, this.getJSON(this.getUrl("Users/" + this.getCurrentUserId() + "/Items/Latest", options))
}, ApiClient.prototype.getFilters = function(options) {
return this.getJSON(this.getUrl("Items/Filters2", options))
}, ApiClient.prototype.supportsWakeOnLan = function() {
return !!wakeOnLan.isSupported() && getCachedWakeOnLanInfo(this).length > 0
}, ApiClient.prototype.wakeOnLan = function() {
var infos = getCachedWakeOnLanInfo(this);
return new Promise(function(resolve, reject) {
sendNextWakeOnLan(infos, 0, resolve)
})
}, ApiClient.prototype.setSystemInfo = function(info) {
this._serverVersion = info.Version
}, ApiClient.prototype.serverVersion = function() {
+1 -1
View File
@@ -24,6 +24,6 @@ define(["events", "appStorage"], function(events, appStorage) {
var existing = list.filter(function(s) {
return s.Id === server.Id
})[0];
return existing ? (existing.DateLastAccessed = Math.max(existing.DateLastAccessed || 0, server.DateLastAccessed || 0), existing.UserLinkType = server.UserLinkType, server.AccessToken && (existing.AccessToken = server.AccessToken, existing.UserId = server.UserId), server.ExchangeToken && (existing.ExchangeToken = server.ExchangeToken), server.RemoteAddress && (existing.RemoteAddress = server.RemoteAddress), server.ManualAddress && (existing.ManualAddress = server.ManualAddress), server.LocalAddress && (existing.LocalAddress = server.LocalAddress), server.Name && (existing.Name = server.Name), server.WakeOnLanInfos && server.WakeOnLanInfos.length && (existing.WakeOnLanInfos = server.WakeOnLanInfos), null != server.LastConnectionMode && (existing.LastConnectionMode = server.LastConnectionMode), server.ConnectServerId && (existing.ConnectServerId = server.ConnectServerId), existing) : (list.push(server), server)
return existing ? (existing.DateLastAccessed = Math.max(existing.DateLastAccessed || 0, server.DateLastAccessed || 0), existing.UserLinkType = server.UserLinkType, server.AccessToken && (existing.AccessToken = server.AccessToken, existing.UserId = server.UserId), server.ExchangeToken && (existing.ExchangeToken = server.ExchangeToken), server.RemoteAddress && (existing.RemoteAddress = server.RemoteAddress), server.ManualAddress && (existing.ManualAddress = server.ManualAddress), server.LocalAddress && (existing.LocalAddress = server.LocalAddress), server.Name && (existing.Name = server.Name), null != server.LastConnectionMode && (existing.LastConnectionMode = server.LastConnectionMode), server.ConnectServerId && (existing.ConnectServerId = server.ConnectServerId), existing) : (list.push(server), server)
}, Credentials
});
@@ -1,158 +1,113 @@
.actionSheet,
.actionSheetContent {
display: -webkit-box;
display: -webkit-flex
}
.actionSheetContent,
.actionSheetScroller {
-webkit-box-orient: vertical;
-webkit-box-direction: normal
}
.actionSheet {
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
padding: 0;
border: none;
max-height: 84%;
-webkit-border-radius: .1em !important;
border-radius: .1em !important
border-radius: .1em !important;
}
.actionsheet-not-fullscreen {
max-width: 90%;
max-height: 90%
max-height: 90%;
}
.actionsheet-fullscreen {
max-height: none;
-webkit-border-radius: 0 !important;
border-radius: 0 !important
border-radius: 0 !important;
}
.actionSheetContent-centered {
text-align: center;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center
align-items: center;
}
.actionSheetContent {
margin: 0 !important;
padding: .4em 0 !important;
-webkit-flex-direction: column;
flex-direction: column;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
overflow: hidden
overflow: hidden;
}
.actionSheetMenuItem {
font-weight: inherit;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.actionSheetMenuItem:focus {
-webkit-transform: none !important;
transform: none !important
}
.actionSheetMenuItem:focus {
transform: none !important;
}
.actionsheetListItemBody {
padding: .4em 1em .4em .6em !important
padding: .4em 1em .4em .6em !important;
}
.actionSheetItemText {
white-space: nowrap;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
vertical-align: middle;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start
justify-content: flex-start;
}
.actionSheetItemAsideText {
opacity: .7;
font-size: 90%;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end;
-webkit-flex-shrink: 0;
flex-shrink: 0;
margin-left: 5em;
margin-right: .5em
margin-right: .5em;
}
.actionSheetScroller {
/* Override default style being applied by polymer */
margin-bottom: 0 !important;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
width: 100%
width: 100%;
}
.actionSheetScroller-tv {
max-height: 64%;
max-width: 60%;
width: auto
width: auto;
}
.actionsheetDivider {
height: .07em;
margin: .25em 0;
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.actionSheetTitle {
margin: .6em 0 .7em !important;
padding: 0 .9em;
-webkit-box-flex: 0;
-webkit-flex-grow: 0;
flex-grow: 0
flex-grow: 0;
}
.actionSheetText {
padding: 0 1em;
-webkit-box-flex: 0;
-webkit-flex-grow: 0;
flex-grow: 0
flex-grow: 0;
}
.actionsheetMenuItemIcon {
margin: 0 .85em 0 .45em !important;
padding: 0 !important
padding: 0 !important;
}
.actionsheet-xlargeFont {
font-size: 112% !important
font-size: 112%!important;
}
.btnCloseActionSheet {
position: fixed;
top: .75em;
left: .5em
}
left: .5em;
}
@@ -1,93 +1,363 @@
define(["dialogHelper", "layoutManager", "globalize", "browser", "dom", "emby-button", "css!./actionsheet", "material-icons", "scrollStyles", "listViewStyle"], function(dialogHelper, layoutManager, globalize, browser, dom) {
"use strict";
define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-button', 'css!./actionsheet', 'material-icons', 'scrollStyles', 'listViewStyle'], function (dialogHelper, layoutManager, globalize, browser, dom) {
'use strict';
function getOffsets(elems) {
var doc = document,
results = [];
if (!doc) return results;
for (var box, elem, i = 0, length = elems.length; i < length; i++) elem = elems[i], box = elem.getBoundingClientRect ? elem.getBoundingClientRect() : {
top: 0,
left: 0
}, results[i] = {
top: box.top,
left: box.left,
width: box.width,
height: box.height
};
return results
var doc = document;
var results = [];
if (!doc) {
return results;
}
var box;
var elem;
for (var i = 0, length = elems.length; i < length; i++) {
elem = elems[i];
// Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) {
box = elem.getBoundingClientRect();
} else {
box = { top: 0, left: 0 };
}
results[i] = {
top: box.top,
left: box.left,
width: box.width,
height: box.height
};
}
return results;
}
function getPosition(options, dlg) {
var windowSize = dom.getWindowSize(),
windowHeight = windowSize.innerHeight,
windowWidth = windowSize.innerWidth;
if (windowWidth < 600 || windowHeight < 600) return null;
var windowSize = dom.getWindowSize();
var windowHeight = windowSize.innerHeight;
var windowWidth = windowSize.innerWidth;
if (windowWidth < 600 || windowHeight < 600) {
return null;
}
var pos = getOffsets([options.positionTo])[0];
"top" !== options.positionY && (pos.top += (pos.height || 0) / 2), pos.left += (pos.width || 0) / 2;
var height = dlg.offsetHeight || 300,
width = dlg.offsetWidth || 160;
pos.top -= height / 2, pos.left -= width / 2;
var overflowX = pos.left + width - windowWidth,
overflowY = pos.top + height - windowHeight;
return overflowX > 0 && (pos.left -= overflowX + 20), overflowY > 0 && (pos.top -= overflowY + 20), pos.top += options.offsetTop || 0, pos.left += options.offsetLeft || 0, pos.top = Math.max(pos.top, 10), pos.left = Math.max(pos.left, 10), pos
if (options.positionY !== 'top') {
pos.top += (pos.height || 0) / 2;
}
pos.left += (pos.width || 0) / 2;
var height = dlg.offsetHeight || 300;
var width = dlg.offsetWidth || 160;
// Account for popup size
pos.top -= height / 2;
pos.left -= width / 2;
// Avoid showing too close to the bottom
var overflowX = pos.left + width - windowWidth;
var overflowY = pos.top + height - windowHeight;
if (overflowX > 0) {
pos.left -= (overflowX + 20);
}
if (overflowY > 0) {
pos.top -= (overflowY + 20);
}
pos.top += (options.offsetTop || 0);
pos.left += (options.offsetLeft || 0);
// Do some boundary checking
pos.top = Math.max(pos.top, 10);
pos.left = Math.max(pos.left, 10);
return pos;
}
function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) {
var fn = on ? "on" : "off";
scrollHelper.centerFocus[fn](elem, horiz)
})
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function show(options) {
var isFullscreen, dialogOptions = {
removeOnClose: !0,
// items
// positionTo
// showCancel
// title
var dialogOptions = {
removeOnClose: true,
enableHistory: options.enableHistory,
scrollY: !1
scrollY: false
};
layoutManager.tv ? (dialogOptions.size = "fullscreen", isFullscreen = !0, !0, dialogOptions.autoFocus = !0) : (dialogOptions.modal = !1, dialogOptions.entryAnimation = options.entryAnimation, dialogOptions.exitAnimation = options.exitAnimation, dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140, dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100, dialogOptions.autoFocus = !1);
var dlg = dialogHelper.createDialog(dialogOptions);
isFullscreen ? dlg.classList.add("actionsheet-fullscreen") : dlg.classList.add("actionsheet-not-fullscreen"), dlg.classList.add("actionSheet"), options.dialogClass && dlg.classList.add(options.dialogClass);
var html = "",
scrollClassName = layoutManager.tv ? "scrollY smoothScrollY hiddenScrollY" : "scrollY",
style = "";
if (options.items.length > 20) {
style += "min-width:" + (dom.getWindowSize().innerWidth >= 300 ? 240 : 200) + "px;"
var backButton = false;
var isFullscreen;
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
isFullscreen = true;
backButton = true;
dialogOptions.autoFocus = true;
} else {
dialogOptions.modal = false;
dialogOptions.entryAnimation = options.entryAnimation;
dialogOptions.exitAnimation = options.exitAnimation;
dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140;
dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100;
dialogOptions.autoFocus = false;
}
var i, length, option, itemIcon, renderIcon = !1,
icons = [];
for (i = 0, length = options.items.length; i < length; i++) option = options.items[i], itemIcon = option.icon || (option.selected ? "check" : null), itemIcon && (renderIcon = !0), icons.push(itemIcon || "");
layoutManager.tv && (html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>');
var center = options.title && !renderIcon;
center || layoutManager.tv ? html += '<div class="actionSheetContent actionSheetContent-centered">' : html += '<div class="actionSheetContent">', options.title && (html += '<h1 class="actionSheetTitle">', html += options.title, html += "</h1>"), options.text && (html += '<p class="actionSheetText">', html += options.text, html += "</p>");
var scrollerClassName = "actionSheetScroller";
layoutManager.tv && (scrollerClassName += " actionSheetScroller-tv focuscontainer-x focuscontainer-y"), html += '<div class="' + scrollerClassName + " " + scrollClassName + '" style="' + style + '">';
var menuItemClass = "listItem listItem-button actionSheetMenuItem";
for ((options.border || options.shaded) && (menuItemClass += " listItem-border"), options.menuItemClass && (menuItemClass += " " + options.menuItemClass), layoutManager.tv && (menuItemClass += " listItem-focusscale"), layoutManager.mobile && (menuItemClass += " actionsheet-xlargeFont"), i = 0, length = options.items.length; i < length; i++)
if (option = options.items[i], option.divider) html += '<div class="actionsheetDivider"></div>';
else {
var autoFocus = option.selected && layoutManager.tv ? " autoFocus" : "",
optionId = null == option.id || "" === option.id ? option.value : option.id;
html += "<button" + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">', itemIcon = icons[i], itemIcon ? html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon">' + itemIcon + "</i>" : renderIcon && !center && (html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon" style="visibility:hidden;">check</i>'), html += '<div class="listItemBody actionsheetListItemBody">', html += '<div class="listItemBodyText actionSheetItemText">', html += option.name || option.textContent || option.innerText, html += "</div>", option.secondaryText && (html += '<div class="listItemBodyText secondary">', html += option.secondaryText, html += "</div>"), html += "</div>", option.asideText && (html += '<div class="listItemAside actionSheetItemAsideText">', html += option.asideText, html += "</div>"), html += "</button>"
} options.showCancel && (html += '<div class="buttons">', html += '<button is="emby-button" type="button" class="btnCloseActionSheet">' + globalize.translate("sharedcomponents#ButtonCancel") + "</button>", html += "</div>"), html += "</div>", dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".actionSheetScroller"), !1, !0), dlg.querySelector(".btnCloseActionSheet") && dlg.querySelector(".btnCloseActionSheet").addEventListener("click", function() {
dialogHelper.close(dlg)
});
var selectedId, timeout;
return options.timeout && (timeout = setTimeout(function() {
dialogHelper.close(dlg)
}, options.timeout)), new Promise(function(resolve, reject) {
var dlg = dialogHelper.createDialog(dialogOptions);
if (isFullscreen) {
dlg.classList.add('actionsheet-fullscreen');
} else {
dlg.classList.add('actionsheet-not-fullscreen');
}
dlg.classList.add('actionSheet');
if (options.dialogClass) {
dlg.classList.add(options.dialogClass);
}
var html = '';
var scrollClassName = layoutManager.tv ? 'scrollY smoothScrollY hiddenScrollY' : 'scrollY';
var style = '';
// Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
if (options.items.length > 20) {
var minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200;
style += "min-width:" + minWidth + "px;";
}
var i, length, option;
var renderIcon = false;
var icons = [];
var itemIcon;
for (i = 0, length = options.items.length; i < length; i++) {
option = options.items[i];
itemIcon = option.icon || (option.selected ? 'check' : null);
if (itemIcon) {
renderIcon = true;
}
icons.push(itemIcon || '');
}
if (layoutManager.tv) {
html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>';
}
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly
var center = options.title && (!renderIcon /*|| itemsWithIcons.length != options.items.length*/);
if (center || layoutManager.tv) {
html += '<div class="actionSheetContent actionSheetContent-centered">';
} else {
html += '<div class="actionSheetContent">';
}
if (options.title) {
html += '<h1 class="actionSheetTitle">';
html += options.title;
html += '</h1>';
}
if (options.text) {
html += '<p class="actionSheetText">';
html += options.text;
html += '</p>';
}
var scrollerClassName = 'actionSheetScroller';
if (layoutManager.tv) {
scrollerClassName += ' actionSheetScroller-tv focuscontainer-x focuscontainer-y';
}
html += '<div class="' + scrollerClassName + ' ' + scrollClassName + '" style="' + style + '">';
var menuItemClass = 'listItem listItem-button actionSheetMenuItem';
if (options.border || options.shaded) {
menuItemClass += ' listItem-border';
}
if (options.menuItemClass) {
menuItemClass += ' ' + options.menuItemClass;
}
if (layoutManager.tv) {
menuItemClass += ' listItem-focusscale';
}
if (layoutManager.mobile) {
menuItemClass += ' actionsheet-xlargeFont';
}
for (i = 0, length = options.items.length; i < length; i++) {
option = options.items[i];
if (option.divider) {
html += '<div class="actionsheetDivider"></div>';
continue;
}
var autoFocus = option.selected && layoutManager.tv ? ' autoFocus' : '';
// Check for null in case int 0 was passed in
var optionId = option.id == null || option.id === '' ? option.value : option.id;
html += '<button' + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">';
itemIcon = icons[i];
if (itemIcon) {
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon">' + itemIcon + '</i>';
}
else if (renderIcon && !center) {
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon" style="visibility:hidden;">check</i>';
}
html += '<div class="listItemBody actionsheetListItemBody">';
html += '<div class="listItemBodyText actionSheetItemText">';
html += (option.name || option.textContent || option.innerText);
html += '</div>';
if (option.secondaryText) {
html += '<div class="listItemBodyText secondary">';
html += option.secondaryText;
html += '</div>';
}
html += '</div>';
if (option.asideText) {
html += '<div class="listItemAside actionSheetItemAsideText">';
html += option.asideText;
html += '</div>';
}
html += '</button>';
}
if (options.showCancel) {
html += '<div class="buttons">';
html += '<button is="emby-button" type="button" class="btnCloseActionSheet">' + globalize.translate('sharedcomponents#ButtonCancel') + '</button>';
html += '</div>';
}
html += '</div>';
dlg.innerHTML = html;
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
}
var btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
if (btnCloseActionSheet) {
dlg.querySelector('.btnCloseActionSheet').addEventListener('click', function () {
dialogHelper.close(dlg);
});
}
// Seeing an issue in some non-chrome browsers where this is requiring a double click
//var eventName = browser.firefox ? 'mousedown' : 'click';
var selectedId;
var timeout;
if (options.timeout) {
timeout = setTimeout(function () {
dialogHelper.close(dlg);
}, options.timeout);
}
return new Promise(function (resolve, reject) {
var isResolved;
dlg.addEventListener("click", function(e) {
var actionSheetMenuItem = dom.parentWithClass(e.target, "actionSheetMenuItem");
actionSheetMenuItem && (selectedId = actionSheetMenuItem.getAttribute("data-id"), options.resolveOnClick && (options.resolveOnClick.indexOf ? -1 !== options.resolveOnClick.indexOf(selectedId) && (resolve(selectedId), isResolved = !0) : (resolve(selectedId), isResolved = !0)), dialogHelper.close(dlg))
}), dlg.addEventListener("close", function() {
layoutManager.tv && centerFocus(dlg.querySelector(".actionSheetScroller"), !1, !1), timeout && (clearTimeout(timeout), timeout = null), isResolved || (null != selectedId ? (options.callback && options.callback(selectedId), resolve(selectedId)) : reject())
}), dialogHelper.open(dlg);
var pos = options.positionTo && "fullscreen" !== dialogOptions.size ? getPosition(options, dlg) : null;
pos && (dlg.style.position = "fixed", dlg.style.margin = 0, dlg.style.left = pos.left + "px", dlg.style.top = pos.top + "px")
})
dlg.addEventListener('click', function (e) {
var actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
if (actionSheetMenuItem) {
selectedId = actionSheetMenuItem.getAttribute('data-id');
if (options.resolveOnClick) {
if (options.resolveOnClick.indexOf) {
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
resolve(selectedId);
isResolved = true;
}
} else {
resolve(selectedId);
isResolved = true;
}
}
dialogHelper.close(dlg);
}
});
dlg.addEventListener('close', function () {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
}
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
if (!isResolved) {
if (selectedId != null) {
if (options.callback) {
options.callback(selectedId);
}
resolve(selectedId);
} else {
reject();
}
}
});
dialogHelper.open(dlg);
var pos = options.positionTo && dialogOptions.size !== 'fullscreen' ? getPosition(options, dlg) : null;
if (pos) {
dlg.style.position = 'fixed';
dlg.style.margin = 0;
dlg.style.left = pos.left + 'px';
dlg.style.top = pos.top + 'px';
}
});
}
return {
show: show
}
};
});
+31 -15
View File
@@ -1,18 +1,34 @@
define(["dialog", "globalize"], function(dialog, globalize) {
"use strict";
return function(text, title) {
define(['dialog', 'globalize'], function (dialog, globalize) {
'use strict';
return function (text, title) {
var options;
options = "string" == typeof text ? {
title: title,
text: text
} : text;
if (typeof text === 'string') {
options = {
title: title,
text: text
};
} else {
options = text;
}
var items = [];
return items.push({
name: globalize.translate("sharedcomponents#ButtonGotIt"),
id: "ok",
type: "submit"
}), options.buttons = items, dialog(options).then(function(result) {
return "ok" === result ? Promise.resolve() : Promise.reject()
})
}
items.push({
name: globalize.translate('sharedcomponents#ButtonGotIt'),
id: 'ok',
type: 'submit'
});
options.buttons = items;
return dialog(options).then(function (result) {
if (result === 'ok') {
return Promise.resolve();
}
return Promise.reject();
});
};
});
+19 -10
View File
@@ -1,14 +1,23 @@
define([], function() {
"use strict";
define([], function () {
'use strict';
function replaceAll(str, find, replace) {
return str.split(find).join(replace)
}
return function(options) {
"string" == typeof options && (options = {
text: options
});
var text = replaceAll(options.text || "", "<br/>", "\n");
return alert(text), Promise.resolve()
return str.split(find).join(replace);
}
return function (options) {
if (typeof options === 'string') {
options = {
text: options
};
}
var text = replaceAll(options.text || '', '<br/>', '\n');
alert(text);
return Promise.resolve();
};
});
@@ -1,59 +1,130 @@
define(["dom", "focusManager"], function(dom, focusManager) {
"use strict";
define(['dom', 'focusManager'], function (dom, focusManager) {
'use strict';
var inputDisplayElement;
var currentDisplayText = '';
var currentDisplayTextContainer;
function onKeyDown(e) {
if (!e.ctrlKey && !e.shiftKey && !e.altKey) {
var key = e.key,
chr = key ? alphanumeric(key) : null;
chr && (chr = chr.toString().toUpperCase(), 1 === chr.length && (currentDisplayTextContainer = this.options.itemsContainer, onAlphanumericKeyPress(e, chr)))
if (e.ctrlKey) {
return;
}
if (!!e.shiftKey) {
return;
}
if (e.altKey) {
return;
}
var key = e.key;
var chr = key ? alphanumeric(key) : null;
if (chr) {
chr = chr.toString().toUpperCase();
if (chr.length === 1) {
currentDisplayTextContainer = this.options.itemsContainer;
onAlphanumericKeyPress(e, chr);
}
}
}
function alphanumeric(value) {
var letterNumber = /^[0-9a-zA-Z]+$/;
return value.match(letterNumber)
return value.match(letterNumber);
}
function ensureInputDisplayElement() {
inputDisplayElement || (inputDisplayElement = document.createElement("div"), inputDisplayElement.classList.add("alphanumeric-shortcut"), inputDisplayElement.classList.add("hide"), document.body.appendChild(inputDisplayElement))
if (!inputDisplayElement) {
inputDisplayElement = document.createElement('div');
inputDisplayElement.classList.add('alphanumeric-shortcut');
inputDisplayElement.classList.add('hide');
document.body.appendChild(inputDisplayElement);
}
}
var alpanumericShortcutTimeout;
function clearAlphaNumericShortcutTimeout() {
alpanumericShortcutTimeout && (clearTimeout(alpanumericShortcutTimeout), alpanumericShortcutTimeout = null)
if (alpanumericShortcutTimeout) {
clearTimeout(alpanumericShortcutTimeout);
alpanumericShortcutTimeout = null;
}
}
function resetAlphaNumericShortcutTimeout() {
clearAlphaNumericShortcutTimeout(), alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2e3)
clearAlphaNumericShortcutTimeout();
alpanumericShortcutTimeout = setTimeout(onAlphanumericShortcutTimeout, 2000);
}
function onAlphanumericKeyPress(e, chr) {
currentDisplayText.length >= 3 || (ensureInputDisplayElement(), currentDisplayText += chr, inputDisplayElement.innerHTML = currentDisplayText, inputDisplayElement.classList.remove("hide"), resetAlphaNumericShortcutTimeout())
if (currentDisplayText.length >= 3) {
return;
}
ensureInputDisplayElement();
currentDisplayText += chr;
inputDisplayElement.innerHTML = currentDisplayText;
inputDisplayElement.classList.remove('hide');
resetAlphaNumericShortcutTimeout();
}
function onAlphanumericShortcutTimeout() {
var value = currentDisplayText,
container = currentDisplayTextContainer;
currentDisplayText = "", currentDisplayTextContainer = null, inputDisplayElement.innerHTML = "", inputDisplayElement.classList.add("hide"), clearAlphaNumericShortcutTimeout(), selectByShortcutValue(container, value)
var value = currentDisplayText;
var container = currentDisplayTextContainer;
currentDisplayText = '';
currentDisplayTextContainer = null;
inputDisplayElement.innerHTML = '';
inputDisplayElement.classList.add('hide');
clearAlphaNumericShortcutTimeout();
selectByShortcutValue(container, value);
}
function selectByShortcutValue(container, value) {
value = value.toUpperCase();
var focusElem;
"#" === value && (focusElem = container.querySelector("*[data-prefix]")), focusElem || (focusElem = container.querySelector("*[data-prefix^='" + value + "']")), focusElem && focusManager.focus(focusElem)
if (value === '#') {
focusElem = container.querySelector('*[data-prefix]');
}
if (!focusElem) {
focusElem = container.querySelector('*[data-prefix^=\'' + value + '\']');
}
if (focusElem) {
focusManager.focus(focusElem);
}
}
function AlphaNumericShortcuts(options) {
this.options = options;
var keyDownHandler = onKeyDown.bind(this);
dom.addEventListener(window, "keydown", keyDownHandler, {
passive: !0
}), this.keyDownHandler = keyDownHandler
dom.addEventListener(window, 'keydown', keyDownHandler, {
passive: true
});
this.keyDownHandler = keyDownHandler;
}
var inputDisplayElement, currentDisplayTextContainer, alpanumericShortcutTimeout, currentDisplayText = "";
return AlphaNumericShortcuts.prototype.destroy = function() {
AlphaNumericShortcuts.prototype.destroy = function () {
var keyDownHandler = this.keyDownHandler;
keyDownHandler && (dom.removeEventListener(window, "keydown", keyDownHandler, {
passive: !0
}), this.keyDownHandler = null), this.options = null
}, AlphaNumericShortcuts
if (keyDownHandler) {
dom.removeEventListener(window, 'keydown', keyDownHandler, {
passive: true
});
this.keyDownHandler = null;
}
this.options = null;
};
return AlphaNumericShortcuts;
});
@@ -1,127 +1,324 @@
define(["focusManager", "layoutManager", "dom", "css!./style.css", "paper-icon-button-light", "material-icons"], function(focusManager, layoutManager, dom) {
"use strict";
define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-button-light', 'material-icons'], function (focusManager, layoutManager, dom) {
'use strict';
var selectedButtonClass = 'alphaPickerButton-selected';
function focus() {
var scope = this,
selected = scope.querySelector("." + selectedButtonClass);
selected ? focusManager.focus(selected) : focusManager.autoFocus(scope, !0)
var scope = this;
var selected = scope.querySelector('.' + selectedButtonClass);
if (selected) {
focusManager.focus(selected);
} else {
focusManager.autoFocus(scope, true);
}
}
function getAlphaPickerButtonClassName(vertical) {
var alphaPickerButtonClassName = "alphaPickerButton";
return layoutManager.tv && (alphaPickerButtonClassName += " alphaPickerButton-tv"), vertical && (alphaPickerButtonClassName += " alphaPickerButton-vertical"), alphaPickerButtonClassName
var alphaPickerButtonClassName = 'alphaPickerButton';
if (layoutManager.tv) {
alphaPickerButtonClassName += ' alphaPickerButton-tv';
}
if (vertical) {
alphaPickerButtonClassName += ' alphaPickerButton-vertical';
}
return alphaPickerButtonClassName;
}
function getLetterButton(l, vertical) {
return '<button data-value="' + l + '" class="' + getAlphaPickerButtonClassName(vertical) + '">' + l + "</button>"
return '<button data-value="' + l + '" class="' + getAlphaPickerButtonClassName(vertical) + '">' + l + '</button>';
}
function mapLetters(letters, vertical) {
return letters.map(function(l) {
return getLetterButton(l, vertical)
})
return letters.map(function (l) {
return getLetterButton(l, vertical);
});
}
function render(element, options) {
element.classList.add("alphaPicker"), layoutManager.tv && element.classList.add("alphaPicker-tv");
var vertical = element.classList.contains("alphaPicker-vertical");
vertical || element.classList.add("focuscontainer-x");
var letters, html = "",
alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical),
rowClassName = "alphaPickerRow";
vertical && (rowClassName += " alphaPickerRow-vertical"), html += '<div class="' + rowClassName + '">', "keyboard" === options.mode ? html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon">&#xE256;</i></button>' : (letters = ["#"], html += mapLetters(letters, vertical).join("")), letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], html += mapLetters(letters, vertical).join(""), "keyboard" === options.mode ? (html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon">&#xE14A;</i></button>', html += "</div>", letters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], html += '<div class="' + rowClassName + '">', html += "<br/>", html += mapLetters(letters, vertical).join(""), html += "</div>") : html += "</div>", element.innerHTML = html, element.classList.add("focusable"), element.focus = focus
element.classList.add('alphaPicker');
if (layoutManager.tv) {
element.classList.add('alphaPicker-tv');
}
var vertical = element.classList.contains('alphaPicker-vertical');
if (vertical) {
} else {
element.classList.add('focuscontainer-x');
}
var html = '';
var letters;
var alphaPickerButtonClassName = getAlphaPickerButtonClassName(vertical);
var rowClassName = 'alphaPickerRow';
if (vertical) {
rowClassName += ' alphaPickerRow-vertical';
}
html += '<div class="' + rowClassName + '">';
if (options.mode === 'keyboard') {
// space_bar icon
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon">&#xE256;</i></button>';
} else {
letters = ['#'];
html += mapLetters(letters, vertical).join('');
}
letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
html += mapLetters(letters, vertical).join('');
if (options.mode === 'keyboard') {
// backspace icon
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon">&#xE14A;</i></button>';
html += '</div>';
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
html += '<div class="' + rowClassName + '">';
html += '<br/>';
html += mapLetters(letters, vertical).join('');
html += '</div>';
} else {
html += '</div>';
}
element.innerHTML = html;
element.classList.add('focusable');
element.focus = focus;
}
function AlphaPicker(options) {
var self = this;
this.options = options;
var element = options.element;
var itemsContainer = options.itemsContainer;
var itemClass = options.itemClass;
var itemFocusValue;
var itemFocusTimeout;
function onItemFocusTimeout() {
itemFocusTimeout = null, self.value(itemFocusValue)
itemFocusTimeout = null;
self.value(itemFocusValue);
}
var alphaFocusedElement;
var alphaFocusTimeout;
function onAlphaFocusTimeout() {
if (alphaFocusTimeout = null, document.activeElement === alphaFocusedElement) {
var value = alphaFocusedElement.getAttribute("data-value");
self.value(value, !0)
alphaFocusTimeout = null;
if (document.activeElement === alphaFocusedElement) {
var value = alphaFocusedElement.getAttribute('data-value');
self.value(value, true);
}
}
function onAlphaPickerInKeyboardModeClick(e) {
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute("data-value");
var value = alphaPickerButton.getAttribute('data-value');
element.dispatchEvent(new CustomEvent("alphavalueclicked", {
cancelable: !1,
cancelable: false,
detail: {
value: value
}
}))
}));
}
}
function onAlphaPickerClick(e) {
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
var value = alphaPickerButton.getAttribute("data-value");
(this._currentValue || "").toUpperCase() === value.toUpperCase() ? self.value(null, !0) : self.value(value, !0)
var value = alphaPickerButton.getAttribute('data-value');
if ((this._currentValue || '').toUpperCase() === value.toUpperCase()) {
self.value(null, true);
} else {
self.value(value, true);
}
}
}
function onAlphaPickerFocusIn(e) {
alphaFocusTimeout && (clearTimeout(alphaFocusTimeout), alphaFocusTimeout = null);
var alphaPickerButton = dom.parentWithClass(e.target, "alphaPickerButton");
alphaPickerButton && (alphaFocusedElement = alphaPickerButton, alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600))
if (alphaFocusTimeout) {
clearTimeout(alphaFocusTimeout);
alphaFocusTimeout = null;
}
var alphaPickerButton = dom.parentWithClass(e.target, 'alphaPickerButton');
if (alphaPickerButton) {
alphaFocusedElement = alphaPickerButton;
alphaFocusTimeout = setTimeout(onAlphaFocusTimeout, 600);
}
}
function onItemsFocusIn(e) {
var item = dom.parentWithClass(e.target, itemClass);
if (item) {
var prefix = item.getAttribute("data-prefix");
prefix && prefix.length && (itemFocusValue = prefix[0], itemFocusTimeout && clearTimeout(itemFocusTimeout), itemFocusTimeout = setTimeout(onItemFocusTimeout, 100))
var prefix = item.getAttribute('data-prefix');
if (prefix && prefix.length) {
itemFocusValue = prefix[0];
if (itemFocusTimeout) {
clearTimeout(itemFocusTimeout);
}
itemFocusTimeout = setTimeout(onItemFocusTimeout, 100);
}
}
}
var self = this;
this.options = options;
var itemFocusValue, itemFocusTimeout, alphaFocusedElement, alphaFocusTimeout, element = options.element,
itemsContainer = options.itemsContainer,
itemClass = options.itemClass;
self.enabled = function(enabled) {
enabled ? (itemsContainer && itemsContainer.addEventListener("focus", onItemsFocusIn, !0), "keyboard" === options.mode && element.addEventListener("click", onAlphaPickerInKeyboardModeClick), "click" !== options.valueChangeEvent ? element.addEventListener("focus", onAlphaPickerFocusIn, !0) : element.addEventListener("click", onAlphaPickerClick.bind(this))) : (itemsContainer && itemsContainer.removeEventListener("focus", onItemsFocusIn, !0), element.removeEventListener("click", onAlphaPickerInKeyboardModeClick), element.removeEventListener("focus", onAlphaPickerFocusIn, !0), element.removeEventListener("click", onAlphaPickerClick.bind(this)))
}, render(element, options), this.enabled(!0), this.visible(!0)
}
var selectedButtonClass = "alphaPickerButton-selected";
return AlphaPicker.prototype.value = function(value, applyValue) {
var btn, selected, element = this.options.element;
if (void 0 !== value)
if (null != value) {
if (value = value.toUpperCase(), this._currentValue = value, "keyboard" !== this.options.mode) {
selected = element.querySelector("." + selectedButtonClass);
try {
btn = element.querySelector(".alphaPickerButton[data-value='" + value + "']")
} catch (err) {
console.log("Error in querySelector: " + err)
}
btn && btn !== selected && btn.classList.add(selectedButtonClass), selected && selected !== btn && selected.classList.remove(selectedButtonClass)
self.enabled = function (enabled) {
if (enabled) {
if (itemsContainer) {
itemsContainer.addEventListener('focus', onItemsFocusIn, true);
}
} else this._currentValue = value, (selected = element.querySelector("." + selectedButtonClass)) && selected.classList.remove(selectedButtonClass);
return applyValue && element.dispatchEvent(new CustomEvent("alphavaluechanged", {
cancelable: !1,
detail: {
value: value
if (options.mode === 'keyboard') {
element.addEventListener('click', onAlphaPickerInKeyboardModeClick);
}
if (options.valueChangeEvent !== 'click') {
element.addEventListener('focus', onAlphaPickerFocusIn, true);
} else {
element.addEventListener('click', onAlphaPickerClick.bind(this));
}
} else {
if (itemsContainer) {
itemsContainer.removeEventListener('focus', onItemsFocusIn, true);
}
element.removeEventListener('click', onAlphaPickerInKeyboardModeClick);
element.removeEventListener('focus', onAlphaPickerFocusIn, true);
element.removeEventListener('click', onAlphaPickerClick.bind(this));
}
})), this._currentValue
}, AlphaPicker.prototype.on = function(name, fn) {
this.options.element.addEventListener(name, fn)
}, AlphaPicker.prototype.off = function(name, fn) {
this.options.element.removeEventListener(name, fn)
}, AlphaPicker.prototype.visible = function(visible) {
this.options.element.style.visibility = visible ? "visible" : "hidden"
}, AlphaPicker.prototype.values = function() {
for (var element = this.options.element, elems = element.querySelectorAll(".alphaPickerButton"), values = [], i = 0, length = elems.length; i < length; i++) values.push(elems[i].getAttribute("data-value"));
return values
}, AlphaPicker.prototype.focus = function() {
};
render(element, options);
this.enabled(true);
this.visible(true);
}
AlphaPicker.prototype.value = function (value, applyValue) {
var element = this.options.element;
focusManager.autoFocus(element, !0)
}, AlphaPicker.prototype.destroy = function() {
var btn, selected;
if (value !== undefined) {
if (value != null) {
value = value.toUpperCase();
this._currentValue = value;
if (this.options.mode !== 'keyboard') {
selected = element.querySelector('.' + selectedButtonClass);
try {
btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
} catch (err) {
console.log('Error in querySelector: ' + err);
}
if (btn && btn !== selected) {
btn.classList.add(selectedButtonClass);
}
if (selected && selected !== btn) {
selected.classList.remove(selectedButtonClass);
}
}
} else {
this._currentValue = value;
selected = element.querySelector('.' + selectedButtonClass);
if (selected) {
selected.classList.remove(selectedButtonClass);
}
}
}
if (applyValue) {
element.dispatchEvent(new CustomEvent("alphavaluechanged", {
cancelable: false,
detail: {
value: value
}
}));
}
return this._currentValue;
};
AlphaPicker.prototype.on = function (name, fn) {
var element = this.options.element;
this.enabled(!1), element.classList.remove("focuscontainer-x"), this.options = null
}, AlphaPicker
element.addEventListener(name, fn);
};
AlphaPicker.prototype.off = function (name, fn) {
var element = this.options.element;
element.removeEventListener(name, fn);
};
AlphaPicker.prototype.visible = function (visible) {
var element = this.options.element;
element.style.visibility = visible ? 'visible' : 'hidden';
};
AlphaPicker.prototype.values = function () {
var element = this.options.element;
var elems = element.querySelectorAll('.alphaPickerButton');
var values = [];
for (var i = 0, length = elems.length; i < length; i++) {
values.push(elems[i].getAttribute('data-value'));
}
return values;
};
AlphaPicker.prototype.focus = function () {
var element = this.options.element;
focusManager.autoFocus(element, true);
};
AlphaPicker.prototype.destroy = function () {
var element = this.options.element;
this.enabled(false);
element.classList.remove('focuscontainer-x');
this.options = null;
};
return AlphaPicker;
});
+41 -65
View File
@@ -1,59 +1,35 @@
.alphaPicker,
.alphaPickerRow {
display: -webkit-box;
display: -webkit-flex;
-webkit-box-direction: normal
}
.alphaPicker,
.alphaPickerRow,
.alphaPickerRow-vertical {
-webkit-box-direction: normal
}
.alphaPicker {
text-align: center;
display: flex;
-webkit-box-orient: vertical;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-align-self: center;
align-self: center
align-self: center;
}
.alphaPicker-vertical {
line-height: 1
line-height: 1;
}
.alphaPicker-fixed {
position: fixed;
bottom: 5.5em;
z-index: 999999
z-index: 999999;
}
.alphaPickerRow {
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-orient: horizontal;
-webkit-flex-direction: row;
flex-direction: row
flex-direction: row;
}
.alphaPickerRow-vertical {
-webkit-box-orient: vertical;
-webkit-flex-direction: column;
flex-direction: column
flex-direction: column;
}
.alphaPickerButton {
border: 0 !important;
cursor: pointer;
outline: 0 !important;
outline: none !important;
vertical-align: middle;
font-family: inherit;
font-size: inherit;
@@ -61,103 +37,103 @@
margin: 0;
padding: .1em .4em;
width: auto;
-webkit-border-radius: .1em;
border-radius: .1em;
font-weight: 400;
-webkit-flex-shrink: 0;
font-weight: normal;
flex-shrink: 0;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1
flex-grow: 1;
}
@media all and (max-height:50em) {
@media all and (max-height: 50em) {
.alphaPicker-fixed {
bottom: 5em
bottom: 5em;
}
.alphaPickerButton-vertical {
padding-top: 1px !important;
padding-bottom: 1px !important
padding-bottom: 1px !important;
}
}
@media all and (max-height:49em) {
@media all and (max-height: 49em) {
.alphaPicker-vertical {
font-size: 94%
font-size: 94%;
}
}
@media all and (max-height:44em) {
@media all and (max-height: 44em) {
.alphaPicker-vertical {
font-size: 90%
font-size: 90%;
}
.alphaPickerButton-vertical {
padding-top: 0 !important;
padding-bottom: 0 !important
padding-bottom: 0 !important;
}
}
@media all and (max-height:37em) {
@media all and (max-height: 37em) {
.alphaPicker-vertical {
font-size: 82%
font-size: 82%;
}
}
@media all and (max-height:32em) {
@media all and (max-height: 32em) {
.alphaPicker-vertical {
font-size: 74%
font-size: 74%;
}
}
.alphaPicker-vertical.alphaPicker-tv {
font-size: 86%
font-size: 86%;
}
.alphaPickerButton-tv.alphaPickerButton-vertical {
padding: 0
padding: 0;
}
.alphaPickerButton-vertical {
/* Assign a fixed width to ensure they have the same dimensions and avoid throwing off directional navigation */
width: 1.5em;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
text-align: center
text-align: center;
}
.alphaPickerButtonIcon {
font-size: 100% !important
font-size: 100% !important;
}
.alphaPicker-fixed.alphaPicker-tv {
bottom: 1%
bottom: 1%;
}
.alphaPicker-fixed-left {
left: .4em
left: .4em;
}
.alphaPicker-fixed-right {
right: .4em
right: .4em;
}
@media all and (min-width:62.5em) {
@media all and (min-width: 62.5em) {
.alphaPicker-fixed-left {
left: 1em
left: 1em;
}
.alphaPicker-fixed-right {
right: 1em
right: 1em;
}
}
@media all and (max-height:31.25em) {
@media all and (max-height: 31.25em) {
.alphaPicker-fixed {
display: none !important
display: none !important;
}
}
}
@@ -1,16 +1,13 @@
.appfooter {
.appfooter {
position: fixed;
left: 0;
right: 0;
z-index: 1;
bottom: 0;
-webkit-transition: -webkit-transform 180ms linear;
-o-transition: transform 180ms linear;
transition: transform 180ms linear;
contain: layout style
contain: layout style;
}
.appfooter.headroom--unpinned {
-webkit-transform: translateY(100%) !important;
transform: translateY(100%) !important
}
.appfooter.headroom--unpinned {
transform: translateY(100%)!important;
}
@@ -1,20 +1,46 @@
define(["browser", "css!./appfooter"], function(browser) {
"use strict";
define(['browser', 'css!./appfooter'], function (browser) {
'use strict';
function render(options) {
var elem = document.createElement("div");
return elem.classList.add("appfooter"), browser.chrome || elem.classList.add("appfooter-blurred"), document.body.appendChild(elem), elem
var elem = document.createElement('div');
elem.classList.add('appfooter');
if (!browser.chrome) {
// chrome does not display this properly
elem.classList.add('appfooter-blurred');
}
document.body.appendChild(elem);
return elem;
}
function appFooter(options) {
var self = this;
self.element = render(options), self.add = function(elem) {
self.element.appendChild(elem)
}, self.insert = function(elem) {
"string" == typeof elem ? self.element.insertAdjacentHTML("afterbegin", elem) : self.element.insertBefore(elem, self.element.firstChild)
}
self.element = render(options);
self.add = function (elem) {
self.element.appendChild(elem);
};
self.insert = function (elem) {
if (typeof elem === 'string') {
self.element.insertAdjacentHTML('afterbegin', elem);
} else {
self.element.insertBefore(elem, self.element.firstChild);
}
};
}
return appFooter.prototype.destroy = function() {
this.element = null
}, appFooter
appFooter.prototype.destroy = function () {
var self = this;
self.element = null;
};
return appFooter;
});
+150 -33
View File
@@ -1,39 +1,156 @@
define(["appStorage", "events"], function(appStorage, events) {
"use strict";
define(['appStorage', 'events'], function (appStorage, events) {
'use strict';
function getKey(name, userId) {
return userId && (name = userId + "-" + name), name
if (userId) {
name = userId + '-' + name;
}
return name;
}
function AppSettings() {}
return AppSettings.prototype.enableAutoLogin = function(val) {
return null != val && this.set("enableAutoLogin", val.toString()), "false" !== this.get("enableAutoLogin")
}, AppSettings.prototype.enableAutomaticBitrateDetection = function(isInNetwork, mediaType, val) {
var key = "enableautobitratebitrate-" + mediaType + "-" + isInNetwork;
return null != val && (isInNetwork && "Audio" === mediaType && (val = !0), this.set(key, val.toString())), !(!isInNetwork || "Audio" !== mediaType) || "false" !== this.get(key)
}, AppSettings.prototype.maxStreamingBitrate = function(isInNetwork, mediaType, val) {
var key = "maxbitrate-" + mediaType + "-" + isInNetwork;
return null != val && (isInNetwork && "Audio" === mediaType || this.set(key, val)), isInNetwork && "Audio" === mediaType ? 15e7 : parseInt(this.get(key) || "0") || 15e5
}, AppSettings.prototype.maxStaticMusicBitrate = function(val) {
void 0 !== val && this.set("maxStaticMusicBitrate", val);
var defaultValue = 32e4;
return parseInt(this.get("maxStaticMusicBitrate") || defaultValue.toString()) || defaultValue
}, AppSettings.prototype.maxChromecastBitrate = function(val) {
return null != val && this.set("chromecastBitrate1", val), val = this.get("chromecastBitrate1"), val ? parseInt(val) : null
}, AppSettings.prototype.syncOnlyOnWifi = function(val) {
return null != val && this.set("syncOnlyOnWifi", val.toString()), "false" !== this.get("syncOnlyOnWifi")
}, AppSettings.prototype.syncPath = function(val) {
return null != val && this.set("syncPath", val), this.get("syncPath")
}, AppSettings.prototype.cameraUploadServers = function(val) {
return null != val && this.set("cameraUploadServers", val.join(",")), val = this.get("cameraUploadServers"), val ? val.split(",") : []
}, AppSettings.prototype.runAtStartup = function(val) {
return null != val && this.set("runatstartup", val.toString()), "true" === this.get("runatstartup")
}, AppSettings.prototype.set = function(name, value, userId) {
function AppSettings() {
}
AppSettings.prototype.enableAutoLogin = function (val) {
if (val != null) {
this.set('enableAutoLogin', val.toString());
}
return this.get('enableAutoLogin') !== 'false';
};
AppSettings.prototype.enableAutomaticBitrateDetection = function (isInNetwork, mediaType, val) {
var key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork;
if (val != null) {
if (isInNetwork && mediaType === 'Audio') {
val = true;
}
this.set(key, val.toString());
}
if (isInNetwork && mediaType === 'Audio') {
return true;
} else {
return this.get(key) !== 'false';
}
};
AppSettings.prototype.maxStreamingBitrate = function (isInNetwork, mediaType, val) {
var key = 'maxbitrate-' + mediaType + '-' + isInNetwork;
if (val != null) {
if (isInNetwork && mediaType === 'Audio') {
// nothing to do, this is always a max value
} else {
this.set(key, val);
}
}
if (isInNetwork && mediaType === 'Audio') {
// return a huge number so that it always direct plays
return 150000000;
} else {
return parseInt(this.get(key) || '0') || 1500000;
}
};
AppSettings.prototype.maxStaticMusicBitrate = function (val) {
if (val !== undefined) {
this.set('maxStaticMusicBitrate', val);
}
var defaultValue = 320000;
return parseInt(this.get('maxStaticMusicBitrate') || defaultValue.toString()) || defaultValue;
};
AppSettings.prototype.maxChromecastBitrate = function (val) {
if (val != null) {
this.set('chromecastBitrate1', val);
}
val = this.get('chromecastBitrate1');
return val ? parseInt(val) : null;
};
AppSettings.prototype.syncOnlyOnWifi = function (val) {
if (val != null) {
this.set('syncOnlyOnWifi', val.toString());
}
return this.get('syncOnlyOnWifi') !== 'false';
};
AppSettings.prototype.syncPath = function (val) {
if (val != null) {
this.set('syncPath', val);
}
return this.get('syncPath');
};
AppSettings.prototype.cameraUploadServers = function (val) {
if (val != null) {
this.set('cameraUploadServers', val.join(','));
}
val = this.get('cameraUploadServers');
if (val) {
return val.split(',');
}
return [];
};
AppSettings.prototype.runAtStartup = function (val) {
if (val != null) {
this.set('runatstartup', val.toString());
}
return this.get('runatstartup') === 'true';
};
AppSettings.prototype.set = function (name, value, userId) {
var currentValue = this.get(name, userId);
appStorage.setItem(getKey(name, userId), value), currentValue !== value && events.trigger(this, "change", [name])
}, AppSettings.prototype.get = function(name, userId) {
return appStorage.getItem(getKey(name, userId))
}, AppSettings.prototype.enableSystemExternalPlayers = function(val) {
return null != val && this.set("enableSystemExternalPlayers", val.toString()), "true" === this.get("enableSystemExternalPlayers")
}, new AppSettings
appStorage.setItem(getKey(name, userId), value);
if (currentValue !== value) {
events.trigger(this, 'change', [name]);
}
};
AppSettings.prototype.get = function (name, userId) {
return appStorage.getItem(getKey(name, userId));
};
AppSettings.prototype.enableSystemExternalPlayers = function (val) {
if (val != null) {
this.set('enableSystemExternalPlayers', val.toString());
}
return this.get('enableSystemExternalPlayers') === 'true';
};
return new AppSettings();
});
+302 -94
View File
@@ -1,150 +1,358 @@
define(["browser", "connectionManager", "playbackManager", "dom", "css!./style"], function(browser, connectionManager, playbackManager, dom) {
"use strict";
define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./style'], function (browser, connectionManager, playbackManager, dom) {
'use strict';
function enableAnimation(elem) {
return !browser.slow
if (browser.slow) {
return false;
}
return true;
}
function enableRotation() {
return !browser.tv && !browser.firefox
if (browser.tv) {
return false;
}
// Causes high cpu usage
if (browser.firefox) {
return false;
}
return true;
}
function Backdrop() {}
function Backdrop() {
}
Backdrop.prototype.load = function (url, parent, existingBackdropImage) {
var img = new Image();
var self = this;
img.onload = function () {
if (self.isDestroyed) {
return;
}
var backdropImage = document.createElement('div');
backdropImage.classList.add('backdropImage');
backdropImage.classList.add('displayingBackdropImage');
backdropImage.style.backgroundImage = "url('" + url + "')";
backdropImage.setAttribute('data-url', url);
backdropImage.classList.add('backdropImageFadeIn');
parent.appendChild(backdropImage);
if (!enableAnimation(backdropImage)) {
if (existingBackdropImage && existingBackdropImage.parentNode) {
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
}
internalBackdrop(true);
return;
}
var onAnimationComplete = function () {
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: true
});
if (backdropImage === self.currentAnimatingElement) {
self.currentAnimatingElement = null;
}
if (existingBackdropImage && existingBackdropImage.parentNode) {
existingBackdropImage.parentNode.removeChild(existingBackdropImage);
}
};
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: true
});
internalBackdrop(true);
};
img.src = url;
};
Backdrop.prototype.cancelAnimation = function () {
var elem = this.currentAnimatingElement;
if (elem) {
elem.classList.remove('backdropImageFadeIn');
this.currentAnimatingElement = null;
}
};
Backdrop.prototype.destroy = function () {
this.isDestroyed = true;
this.cancelAnimation();
};
var backdropContainer;
function getBackdropContainer() {
return backdropContainer || (backdropContainer = document.querySelector(".backdropContainer")), backdropContainer || (backdropContainer = document.createElement("div"), backdropContainer.classList.add("backdropContainer"), document.body.insertBefore(backdropContainer, document.body.firstChild)), backdropContainer
if (!backdropContainer) {
backdropContainer = document.querySelector('.backdropContainer');
}
if (!backdropContainer) {
backdropContainer = document.createElement('div');
backdropContainer.classList.add('backdropContainer');
document.body.insertBefore(backdropContainer, document.body.firstChild);
}
return backdropContainer;
}
function clearBackdrop(clearAll) {
clearRotation(), currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null), getBackdropContainer().innerHTML = "", clearAll && (hasExternalBackdrop = !1), internalBackdrop(!1)
}
function getBackgroundContainer() {
return backgroundContainer || (backgroundContainer = document.querySelector(".backgroundContainer")), backgroundContainer
}
clearRotation();
function setBackgroundContainerBackgroundEnabled() {
hasInternalBackdrop || hasExternalBackdrop ? getBackgroundContainer().classList.add("withBackdrop") : getBackgroundContainer().classList.remove("withBackdrop")
}
function internalBackdrop(enabled) {
hasInternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled()
}
function externalBackdrop(enabled) {
hasExternalBackdrop = enabled, setBackgroundContainerBackgroundEnabled()
}
function setBackdropImage(url) {
currentLoadingBackdrop && (currentLoadingBackdrop.destroy(), currentLoadingBackdrop = null);
var elem = getBackdropContainer(),
existingBackdropImage = elem.querySelector(".displayingBackdropImage");
if (existingBackdropImage && existingBackdropImage.getAttribute("data-url") === url) {
if (existingBackdropImage.getAttribute("data-url") === url) return;
existingBackdropImage.classList.remove("displayingBackdropImage")
if (currentLoadingBackdrop) {
currentLoadingBackdrop.destroy();
currentLoadingBackdrop = null;
}
var instance = new Backdrop;
instance.load(url, elem, existingBackdropImage), currentLoadingBackdrop = instance
var elem = getBackdropContainer();
elem.innerHTML = '';
if (clearAll) {
hasExternalBackdrop = false;
}
internalBackdrop(false);
}
var backgroundContainer;
function getBackgroundContainer() {
if (!backgroundContainer) {
backgroundContainer = document.querySelector('.backgroundContainer');
}
return backgroundContainer;
}
function setBackgroundContainerBackgroundEnabled() {
if (hasInternalBackdrop || hasExternalBackdrop) {
getBackgroundContainer().classList.add('withBackdrop');
} else {
getBackgroundContainer().classList.remove('withBackdrop');
}
}
var hasInternalBackdrop;
function internalBackdrop(enabled) {
hasInternalBackdrop = enabled;
setBackgroundContainerBackgroundEnabled();
}
var hasExternalBackdrop;
function externalBackdrop(enabled) {
hasExternalBackdrop = enabled;
setBackgroundContainerBackgroundEnabled();
}
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
var currentLoadingBackdrop;
function setBackdropImage(url) {
if (currentLoadingBackdrop) {
currentLoadingBackdrop.destroy();
currentLoadingBackdrop = null;
}
var elem = getBackdropContainer();
var existingBackdropImage = elem.querySelector('.displayingBackdropImage');
if (existingBackdropImage && existingBackdropImage.getAttribute('data-url') === url) {
if (existingBackdropImage.getAttribute('data-url') === url) {
return;
}
existingBackdropImage.classList.remove('displayingBackdropImage');
}
var instance = new Backdrop();
instance.load(url, elem, existingBackdropImage);
currentLoadingBackdrop = instance;
}
var standardWidths = [480, 720, 1280, 1440, 1920];
function getBackdropMaxWidth() {
var width = dom.getWindowSize().innerWidth;
if (-1 !== standardWidths.indexOf(width)) return width;
return width = 100 * Math.floor(width / 100), Math.min(width, 1920)
if (standardWidths.indexOf(width) !== -1) {
return width;
}
var roundScreenTo = 100;
width = Math.floor(width / roundScreenTo) * roundScreenTo;
return Math.min(width, 1920);
}
function getItemImageUrls(item, imageOptions) {
imageOptions = imageOptions || {};
var apiClient = connectionManager.getApiClient(item.ServerId);
return item.BackdropImageTags && item.BackdropImageTags.length > 0 ? item.BackdropImageTags.map(function(imgTag, index) {
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
type: "Backdrop",
tag: imgTag,
maxWidth: getBackdropMaxWidth(),
index: index
}))
}) : item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length ? item.ParentBackdropImageTags.map(function(imgTag, index) {
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
type: "Backdrop",
tag: imgTag,
maxWidth: getBackdropMaxWidth(),
index: index
}))
}) : []
if (item.BackdropImageTags && item.BackdropImageTags.length > 0) {
return item.BackdropImageTags.map(function (imgTag, index) {
return apiClient.getScaledImageUrl(item.BackdropItemId || item.Id, Object.assign(imageOptions, {
type: "Backdrop",
tag: imgTag,
maxWidth: getBackdropMaxWidth(),
index: index
}));
});
}
if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
return item.ParentBackdropImageTags.map(function (imgTag, index) {
return apiClient.getScaledImageUrl(item.ParentBackdropItemId, Object.assign(imageOptions, {
type: "Backdrop",
tag: imgTag,
maxWidth: getBackdropMaxWidth(),
index: index
}));
});
}
return [];
}
function getImageUrls(items, imageOptions) {
for (var list = [], onImg = function(img) {
list.push(img)
}, i = 0, length = items.length; i < length; i++) {
getItemImageUrls(items[i], imageOptions).forEach(onImg)
var list = [];
var onImg = function (img) {
list.push(img);
};
for (var i = 0, length = items.length; i < length; i++) {
var itemImages = getItemImageUrls(items[i], imageOptions);
itemImages.forEach(onImg);
}
return list
return list;
}
function arraysEqual(a, b) {
if (a === b) return !0;
if (null == a || null == b) return !1;
if (a.length !== b.length) return !1;
for (var i = 0; i < a.length; ++i)
if (a[i] !== b[i]) return !1;
return !0
if (a === b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length !== b.length) {
return false;
}
// If you don't care about the order of the elements inside
// the array, you should sort both arrays here.
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
var rotationInterval;
var currentRotatingImages = [];
var currentRotationIndex = -1;
function setBackdrops(items, imageOptions, enableImageRotation) {
var images = getImageUrls(items, imageOptions);
images.length ? startRotation(images, enableImageRotation) : clearBackdrop()
if (images.length) {
startRotation(images, enableImageRotation);
} else {
clearBackdrop();
}
}
function startRotation(images, enableImageRotation) {
arraysEqual(images, currentRotatingImages) || (clearRotation(), currentRotatingImages = images, currentRotationIndex = -1, images.length > 1 && !1 !== enableImageRotation && enableRotation() && (rotationInterval = setInterval(onRotationInterval, 24e3)), onRotationInterval())
if (arraysEqual(images, currentRotatingImages)) {
return;
}
clearRotation();
currentRotatingImages = images;
currentRotationIndex = -1;
if (images.length > 1 && enableImageRotation !== false && enableRotation()) {
rotationInterval = setInterval(onRotationInterval, 24000);
}
onRotationInterval();
}
function onRotationInterval() {
if (!playbackManager.isPlayingLocally(["Video"])) {
var newIndex = currentRotationIndex + 1;
newIndex >= currentRotatingImages.length && (newIndex = 0), currentRotationIndex = newIndex, setBackdropImage(currentRotatingImages[newIndex])
if (playbackManager.isPlayingLocally(['Video'])) {
return;
}
var newIndex = currentRotationIndex + 1;
if (newIndex >= currentRotatingImages.length) {
newIndex = 0;
}
currentRotationIndex = newIndex;
setBackdropImage(currentRotatingImages[newIndex]);
}
function clearRotation() {
var interval = rotationInterval;
interval && clearInterval(interval), rotationInterval = null, currentRotatingImages = [], currentRotationIndex = -1
if (interval) {
clearInterval(interval);
}
rotationInterval = null;
currentRotatingImages = [];
currentRotationIndex = -1;
}
function setBackdrop(url, imageOptions) {
url && "string" != typeof url && (url = getImageUrls([url], imageOptions)[0]), url ? (clearRotation(), setBackdropImage(url)) : clearBackdrop()
}
Backdrop.prototype.load = function(url, parent, existingBackdropImage) {
var img = new Image,
self = this;
img.onload = function() {
if (!self.isDestroyed) {
var backdropImage = document.createElement("div");
if (backdropImage.classList.add("backdropImage"), backdropImage.classList.add("displayingBackdropImage"), backdropImage.style.backgroundImage = "url('" + url + "')", backdropImage.setAttribute("data-url", url), backdropImage.classList.add("backdropImageFadeIn"), parent.appendChild(backdropImage), !enableAnimation(backdropImage)) return existingBackdropImage && existingBackdropImage.parentNode && existingBackdropImage.parentNode.removeChild(existingBackdropImage), void internalBackdrop(!0);
var onAnimationComplete = function() {
dom.removeEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: !0
}), backdropImage === self.currentAnimatingElement && (self.currentAnimatingElement = null), existingBackdropImage && existingBackdropImage.parentNode && existingBackdropImage.parentNode.removeChild(existingBackdropImage)
};
dom.addEventListener(backdropImage, dom.whichAnimationEvent(), onAnimationComplete, {
once: !0
}), internalBackdrop(!0)
if (url) {
if (typeof url !== 'string') {
url = getImageUrls([url], imageOptions)[0];
}
}, img.src = url
}, Backdrop.prototype.cancelAnimation = function() {
var elem = this.currentAnimatingElement;
elem && (elem.classList.remove("backdropImageFadeIn"), this.currentAnimatingElement = null)
}, Backdrop.prototype.destroy = function() {
this.isDestroyed = !0, this.cancelAnimation()
};
var backdropContainer, backgroundContainer, hasInternalBackdrop, hasExternalBackdrop, currentLoadingBackdrop, rotationInterval, standardWidths = [480, 720, 1280, 1440, 1920],
currentRotatingImages = [],
currentRotationIndex = -1;
}
if (url) {
clearRotation();
setBackdropImage(url);
} else {
clearBackdrop();
}
}
return {
setBackdrops: setBackdrops,
setBackdrop: setBackdrop,
clear: clearBackdrop,
externalBackdrop: externalBackdrop
}
};
});
+6 -18
View File
@@ -1,41 +1,29 @@
.backdropContainer {
contain: layout style size
contain: layout style size;
}
.backdropImage {
background-repeat: no-repeat;
background-position: center center;
-webkit-background-size: cover;
background-size: cover;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
contain: layout style
contain: layout style;
}
.backdropImageFadeIn {
-webkit-animation: backdrop-fadein .8s ease-in normal both;
animation: backdrop-fadein .8s ease-in normal both
}
@-webkit-keyframes backdrop-fadein {
from {
opacity: 0
}
to {
opacity: 1
}
animation: backdrop-fadein 800ms ease-in normal both;
}
@keyframes backdrop-fadein {
from {
opacity: 0
opacity: 0;
}
to {
opacity: 1
opacity: 1;
}
}
}
+304 -63
View File
@@ -1,69 +1,310 @@
define([], function() {
"use strict";
define([], function () {
'use strict';
function supportsCssAnimation(allowPrefix) {
if (allowPrefix) {
if (!0 === _supportsCssAnimationWithPrefix || !1 === _supportsCssAnimationWithPrefix) return _supportsCssAnimationWithPrefix
} else if (!0 === _supportsCssAnimation || !1 === _supportsCssAnimation) return _supportsCssAnimation;
var animation = !1,
domPrefixes = ["Webkit", "O", "Moz"],
pfx = "",
elm = document.createElement("div");
if (void 0 !== elm.style.animationName && (animation = !0), !1 === animation && allowPrefix)
for (var i = 0; i < domPrefixes.length; i++)
if (void 0 !== elm.style[domPrefixes[i] + "AnimationName"]) {
pfx = domPrefixes[i], pfx + "Animation", "-" + pfx.toLowerCase() + "-", animation = !0;
break
} return allowPrefix ? _supportsCssAnimationWithPrefix = animation : _supportsCssAnimation = animation
function isTv() {
// This is going to be really difficult to get right
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf('tv') !== -1) {
return true;
}
if (userAgent.indexOf('samsungbrowser') !== -1) {
return true;
}
if (userAgent.indexOf('nintendo') !== -1) {
return true;
}
if (userAgent.indexOf('viera') !== -1) {
return true;
}
if (userAgent.indexOf('webos') !== -1) {
return true;
}
return false;
}
var _supportsCssAnimation, _supportsCssAnimationWithPrefix, userAgent = navigator.userAgent,
matched = function(ua) {
ua = ua.toLowerCase();
var match = /(edge)[ \/]([\w.]+)/.exec(ua) || /(opera)[ \/]([\w.]+)/.exec(ua) || /(opr)[ \/]([\w.]+)/.exec(ua) || /(chrome)[ \/]([\w.]+)/.exec(ua) || /(safari)[ \/]([\w.]+)/.exec(ua) || /(firefox)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [],
versionMatch = /(version)[ \/]([\w.]+)/.exec(ua),
platform_match = /(ipad)/.exec(ua) || /(iphone)/.exec(ua) || /(windows)/.exec(ua) || /(android)/.exec(ua) || [],
browser = match[1] || "";
"edge" === browser ? platform_match = [""] : -1 !== ua.indexOf("windows phone") || -1 !== ua.indexOf("iemobile") ? browser = "msie" : -1 !== ua.indexOf("like gecko") && -1 === ua.indexOf("webkit") && -1 === ua.indexOf("opera") && -1 === ua.indexOf("chrome") && -1 === ua.indexOf("safari") && (browser = "msie"), "opr" === browser && (browser = "opera");
var version;
versionMatch && versionMatch.length > 2 && (version = versionMatch[2]), version = version || match[2] || "0";
var versionMajor = parseInt(version.split(".")[0]);
return isNaN(versionMajor) && (versionMajor = 0), {
browser: browser,
version: version,
platform: platform_match[0] || "",
versionMajor: versionMajor
function isMobile(userAgent) {
var terms = [
'mobi',
'ipad',
'iphone',
'ipod',
'silk',
'gt-p1000',
'nexus 7',
'kindle fire',
'opera mini'
];
var lower = userAgent.toLowerCase();
for (var i = 0, length = terms.length; i < length; i++) {
if (lower.indexOf(terms[i]) !== -1) {
return true;
}
}(userAgent),
browser = {};
return matched.browser && (browser[matched.browser] = !0, browser.version = matched.version, browser.versionMajor = matched.versionMajor), matched.platform && (browser[matched.platform] = !0), browser.chrome || browser.msie || browser.edge || browser.opera || -1 === userAgent.toLowerCase().indexOf("webkit") || (browser.safari = !0), -1 !== userAgent.toLowerCase().indexOf("playstation 4") && (browser.ps4 = !0, browser.tv = !0),
function(userAgent) {
for (var terms = ["mobi", "ipad", "iphone", "ipod", "silk", "gt-p1000", "nexus 7", "kindle fire", "opera mini"], lower = userAgent.toLowerCase(), i = 0, length = terms.length; i < length; i++)
if (-1 !== lower.indexOf(terms[i])) return !0;
return !1
}(userAgent) && (browser.mobile = !0), browser.xboxOne = -1 !== userAgent.toLowerCase().indexOf("xbox"), browser.animate = "undefined" != typeof document && null != document.documentElement.animate, browser.tizen = -1 !== userAgent.toLowerCase().indexOf("tizen") || null != self.tizen, browser.web0s = -1 !== userAgent.toLowerCase().indexOf("Web0S".toLowerCase()), browser.edgeUwp = browser.edge && (-1 !== userAgent.toLowerCase().indexOf("msapphost") || -1 !== userAgent.toLowerCase().indexOf("webview")), browser.tizen || (browser.orsay = -1 !== userAgent.toLowerCase().indexOf("smarthub")), browser.edgeUwp && (browser.edge = !0), browser.tv = function() {
var userAgent = navigator.userAgent.toLowerCase();
return -1 !== userAgent.indexOf("tv") || (-1 !== userAgent.indexOf("samsungbrowser") || (-1 !== userAgent.indexOf("nintendo") || (-1 !== userAgent.indexOf("viera") || -1 !== userAgent.indexOf("webos"))))
}(), browser.operaTv = browser.tv && -1 !== userAgent.toLowerCase().indexOf("opr/"),
function(prop, value) {
if ("undefined" == typeof window) return !1;
if (value = 2 === arguments.length ? value : "inherit", "CSS" in window && "supports" in window.CSS) return window.CSS.supports(prop, value);
if ("supportsCSS" in window) return window.supportsCSS(prop, value);
try {
var camel = prop.replace(/-([a-z]|[0-9])/gi, function(all, letter) {
return (letter + "").toUpperCase()
}),
support = camel in el.style,
el = document.createElement("div");
return el.style.cssText = prop + ":" + value, support && "" !== el.style[camel]
} catch (err) {
return !1
}
return false;
}
function isStyleSupported(prop, value) {
if (typeof window === 'undefined') {
return false;
}
// If no value is supplied, use "inherit"
value = arguments.length === 2 ? value : 'inherit';
// Try the native standard method first
if ('CSS' in window && 'supports' in window.CSS) {
return window.CSS.supports(prop, value);
}
// Check Opera's native method
if ('supportsCSS' in window) {
return window.supportsCSS(prop, value);
}
// need try/catch because it's failing on tizen
try {
// Convert to camel-case for DOM interactions
var camel = prop.replace(/-([a-z]|[0-9])/ig, function (all, letter) {
return (letter + '').toUpperCase();
});
// Check if the property is supported
var support = (camel in el.style);
// Create test element
var el = document.createElement('div');
// Assign the property and value to invoke
// the CSS interpreter
el.style.cssText = prop + ':' + value;
// Ensure both the property and value are
// supported and return
return support && (el.style[camel] !== '');
} catch (err) {
return false;
}
}
function hasKeyboard(browser) {
if (browser.touch) {
return true;
}
if (browser.xboxOne) {
return true;
}
if (browser.ps4) {
return true;
}
if (browser.edgeUwp) {
// This is OK for now, but this won't always be true
// Should we use this?
// https://gist.github.com/wagonli/40d8a31bd0d6f0dd7a5d
return true;
}
if (browser.tv) {
return true;
}
return false;
}
function iOSversion() {
if (/iP(hone|od|ad)/.test(navigator.platform)) {
// supports iOS 2.0 and later: <http://bit.ly/TJjs1V>
var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
}
}
var _supportsCssAnimation;
var _supportsCssAnimationWithPrefix;
function supportsCssAnimation(allowPrefix) {
if (allowPrefix) {
if (_supportsCssAnimationWithPrefix === true || _supportsCssAnimationWithPrefix === false) {
return _supportsCssAnimationWithPrefix;
}
}("display", "flex") || (browser.noFlex = !0), (browser.mobile || browser.tv) && (browser.slow = !0), "undefined" != typeof document && ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch) && (browser.touch = !0), browser.keyboard = function(browser) {
return !!browser.touch || (!!browser.xboxOne || (!!browser.ps4 || (!!browser.edgeUwp || !!browser.tv)))
}(browser), browser.supportsCssAnimation = supportsCssAnimation, browser.osx = -1 !== userAgent.toLowerCase().indexOf("os x"), browser.iOS = browser.ipad || browser.iphone || browser.ipod, browser.iOS && (browser.iOSVersion = function() {
if (/iP(hone|od|ad)/.test(navigator.platform)) {
var v = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
return [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)]
} else {
if (_supportsCssAnimation === true || _supportsCssAnimation === false) {
return _supportsCssAnimation;
}
}(), browser.iOSVersion = browser.iOSVersion[0] + browser.iOSVersion[1] / 10), browser.chromecast = browser.chrome && -1 !== userAgent.toLowerCase().indexOf("crkey"), browser
}
var animation = false,
animationstring = 'animation',
keyframeprefix = '',
domPrefixes = ['Webkit', 'O', 'Moz'],
pfx = '',
elm = document.createElement('div');
if (elm.style.animationName !== undefined) { animation = true; }
if (animation === false && allowPrefix) {
for (var i = 0; i < domPrefixes.length; i++) {
if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {
pfx = domPrefixes[i];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
animation = true;
break;
}
}
}
if (allowPrefix) {
_supportsCssAnimationWithPrefix = animation;
return _supportsCssAnimationWithPrefix;
} else {
_supportsCssAnimation = animation;
return _supportsCssAnimation;
}
}
var uaMatch = function (ua) {
ua = ua.toLowerCase();
var match = /(edge)[ \/]([\w.]+)/.exec(ua) ||
/(opera)[ \/]([\w.]+)/.exec(ua) ||
/(opr)[ \/]([\w.]+)/.exec(ua) ||
/(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(safari)[ \/]([\w.]+)/.exec(ua) ||
/(firefox)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
var versionMatch = /(version)[ \/]([\w.]+)/.exec(ua);
var platform_match = /(ipad)/.exec(ua) ||
/(iphone)/.exec(ua) ||
/(windows)/.exec(ua) ||
/(android)/.exec(ua) ||
[];
var browser = match[1] || "";
if (browser === "edge") {
platform_match = [""];
} else {
if (ua.indexOf("windows phone") !== -1 || ua.indexOf("iemobile") !== -1) {
// http://www.neowin.net/news/ie11-fakes-user-agent-to-fool-gmail-in-windows-phone-81-gdr1-update
browser = "msie";
}
else if (ua.indexOf("like gecko") !== -1 && ua.indexOf('webkit') === -1 && ua.indexOf('opera') === -1 && ua.indexOf('chrome') === -1 && ua.indexOf('safari') === -1) {
browser = "msie";
}
}
if (browser === 'opr') {
browser = 'opera';
}
var version;
if (versionMatch && versionMatch.length > 2) {
version = versionMatch[2];
}
version = version || match[2] || "0";
var versionMajor = parseInt(version.split('.')[0]);
if (isNaN(versionMajor)) {
versionMajor = 0;
}
return {
browser: browser,
version: version,
platform: platform_match[0] || "",
versionMajor: versionMajor
};
};
var userAgent = navigator.userAgent;
var matched = uaMatch(userAgent);
var browser = {};
if (matched.browser) {
browser[matched.browser] = true;
browser.version = matched.version;
browser.versionMajor = matched.versionMajor;
}
if (matched.platform) {
browser[matched.platform] = true;
}
if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf("webkit") !== -1) {
browser.safari = true;
}
if (userAgent.toLowerCase().indexOf("playstation 4") !== -1) {
browser.ps4 = true;
browser.tv = true;
}
if (isMobile(userAgent)) {
browser.mobile = true;
}
browser.xboxOne = userAgent.toLowerCase().indexOf('xbox') !== -1;
browser.animate = typeof document !== 'undefined' && document.documentElement.animate != null;
browser.tizen = userAgent.toLowerCase().indexOf('tizen') !== -1 || self.tizen != null;
browser.web0s = userAgent.toLowerCase().indexOf('Web0S'.toLowerCase()) !== -1;
browser.edgeUwp = browser.edge && (userAgent.toLowerCase().indexOf('msapphost') !== -1 || userAgent.toLowerCase().indexOf('webview') !== -1);
if (!browser.tizen) {
browser.orsay = userAgent.toLowerCase().indexOf('smarthub') !== -1;
}
if (browser.edgeUwp) {
browser.edge = true;
}
browser.tv = isTv();
browser.operaTv = browser.tv && userAgent.toLowerCase().indexOf('opr/') !== -1;
if (!isStyleSupported('display', 'flex')) {
browser.noFlex = true;
}
if (browser.mobile || browser.tv) {
browser.slow = true;
}
if (typeof document !== 'undefined') {
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
browser.touch = true;
}
}
browser.keyboard = hasKeyboard(browser);
browser.supportsCssAnimation = supportsCssAnimation;
browser.osx = userAgent.toLowerCase().indexOf('os x') !== -1;
browser.iOS = browser.ipad || browser.iphone || browser.ipod;
if (browser.iOS) {
browser.iOSVersion = iOSversion();
browser.iOSVersion = browser.iOSVersion[0] + (browser.iOSVersion[1] / 10);
}
browser.chromecast = browser.chrome && userAgent.toLowerCase().indexOf('crkey') !== -1;
return browser;
});
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,59 +1,140 @@
define(["datetime", "imageLoader", "connectionManager", "layoutManager", "browser"], function(datetime, imageLoader, connectionManager, layoutManager, browser) {
"use strict";
define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browser'], function (datetime, imageLoader, connectionManager, layoutManager, browser) {
'use strict';
function buildChapterCardsHtml(item, chapters, options) {
var className = "card itemAction chapterCard";
layoutManager.tv && (browser.animate || browser.edge) && (className += " card-focusscale");
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [],
videoStream = mediaStreams.filter(function(i) {
return "Video" === i.Type
})[0] || {},
shape = options.backdropShape || "backdrop";
videoStream.Width && videoStream.Height && videoStream.Width / videoStream.Height <= 1.2 && (shape = options.squareShape || "square"), className += " " + shape + "Card", (options.block || options.rows) && (className += " block");
for (var html = "", itemsInRow = 0, apiClient = connectionManager.getApiClient(item.ServerId), i = 0, length = chapters.length; i < length; i++) {
options.rows && 0 === itemsInRow && (html += '<div class="cardColumn">');
html += buildChapterCard(item, apiClient, chapters[i], i, options, className, shape), itemsInRow++, options.rows && itemsInRow >= options.rows && (itemsInRow = 0, html += "</div>")
var className = 'card itemAction chapterCard';
if (layoutManager.tv && (browser.animate || browser.edge)) {
className += ' card-focusscale';
}
return html
var mediaStreams = ((item.MediaSources || [])[0] || {}).MediaStreams || [];
var videoStream = mediaStreams.filter(function (i) {
return i.Type === 'Video';
})[0] || {};
var shape = (options.backdropShape || 'backdrop');
if (videoStream.Width && videoStream.Height) {
if ((videoStream.Width / videoStream.Height) <= 1.2) {
shape = (options.squareShape || 'square');
}
}
className += ' ' + shape + 'Card';
if (options.block || options.rows) {
className += ' block';
}
var html = '';
var itemsInRow = 0;
var apiClient = connectionManager.getApiClient(item.ServerId);
for (var i = 0, length = chapters.length; i < length; i++) {
if (options.rows && itemsInRow === 0) {
html += '<div class="cardColumn">';
}
var chapter = chapters[i];
html += buildChapterCard(item, apiClient, chapter, i, options, className, shape);
itemsInRow++;
if (options.rows && itemsInRow >= options.rows) {
itemsInRow = 0;
html += '</div>';
}
}
return html;
}
function getImgUrl(item, chapter, index, maxWidth, apiClient) {
return chapter.ImageTag ? apiClient.getScaledImageUrl(item.Id, {
maxWidth: maxWidth,
tag: chapter.ImageTag,
type: "Chapter",
index: index
}) : null
if (chapter.ImageTag) {
return apiClient.getScaledImageUrl(item.Id, {
maxWidth: maxWidth,
tag: chapter.ImageTag,
type: "Chapter",
index: index
});
}
return null;
}
function buildChapterCard(item, apiClient, chapter, index, options, className, shape) {
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient),
cardImageContainerClass = "cardContent cardContent-shadow cardImageContainer chapterCardImageContainer";
options.coverImage && (cardImageContainerClass += " coveredImage");
var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"',
cardImageContainer = imgUrl ? '<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">' : '<div class="' + cardImageContainerClass + '">';
imgUrl || (cardImageContainer += '<i class="md-icon cardImageIcon">local_movies</i>');
var nameHtml = "";
nameHtml += '<div class="cardText">' + chapter.Name + "</div>", nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + "</div>";
var cardBoxCssClass = "cardBox",
cardScalableClass = "cardScalable";
var imgUrl = getImgUrl(item, chapter, index, options.width || 400, apiClient);
var cardImageContainerClass = 'cardContent cardContent-shadow cardImageContainer chapterCardImageContainer';
if (options.coverImage) {
cardImageContainerClass += ' coveredImage';
}
var dataAttributes = ' data-action="play" data-isfolder="' + item.IsFolder + '" data-id="' + item.Id + '" data-serverid="' + item.ServerId + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-positionticks="' + chapter.StartPositionTicks + '"';
var cardImageContainer = imgUrl ? ('<div class="' + cardImageContainerClass + ' lazy" data-src="' + imgUrl + '">') : ('<div class="' + cardImageContainerClass + '">');
if (!imgUrl) {
cardImageContainer += '<i class="md-icon cardImageIcon">local_movies</i>';
}
var nameHtml = '';
nameHtml += '<div class="cardText">' + chapter.Name + '</div>';
nameHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(chapter.StartPositionTicks) + '</div>';
var cardBoxCssClass = 'cardBox';
var cardScalableClass = 'cardScalable';
if (layoutManager.tv) {
var enableFocusTransfrom = !browser.slow && !browser.edge;
cardScalableClass += " card-focuscontent", enableFocusTransfrom ? cardBoxCssClass += " cardBox-focustransform cardBox-withfocuscontent" : (cardBoxCssClass += " cardBox-withfocuscontent-large", cardScalableClass += " card-focuscontent-large")
cardScalableClass += ' card-focuscontent';
if (enableFocusTransfrom) {
cardBoxCssClass += ' cardBox-focustransform cardBox-withfocuscontent';
} else {
cardBoxCssClass += ' cardBox-withfocuscontent-large';
cardScalableClass += ' card-focuscontent-large';
}
}
return '<button type="button" class="' + className + '"' + dataAttributes + '><div class="' + cardBoxCssClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainer + '</div><div class="innerCardFooter">' + nameHtml + "</div></div></div></button>"
var html = '<button type="button" class="' + className + '"' + dataAttributes + '><div class="' + cardBoxCssClass + '"><div class="' + cardScalableClass + '"><div class="cardPadder-' + shape + '"></div>' + cardImageContainer + '</div><div class="innerCardFooter">' + nameHtml + '</div></div></div></button>';
return html;
}
function buildChapterCards(item, chapters, options) {
if (options.parentContainer) {
if (!document.body.contains(options.parentContainer)) return;
if (!chapters.length) return void options.parentContainer.classList.add("hide");
options.parentContainer.classList.remove("hide")
// Abort if the container has been disposed
if (!document.body.contains(options.parentContainer)) {
return;
}
if (chapters.length) {
options.parentContainer.classList.remove('hide');
} else {
options.parentContainer.classList.add('hide');
return;
}
}
var html = buildChapterCardsHtml(item, chapters, options);
options.itemsContainer.innerHTML = html, imageLoader.lazyChildren(options.itemsContainer)
options.itemsContainer.innerHTML = html;
imageLoader.lazyChildren(options.itemsContainer);
}
return {
buildChapterCards: buildChapterCards
}
};
});
@@ -1,18 +1,22 @@
define(["cardBuilder"], function(cardBuilder) {
"use strict";
define(['cardBuilder'], function (cardBuilder) {
'use strict';
function buildPeopleCards(items, options) {
options = Object.assign(options || {}, {
cardLayout: !1,
centerText: !0,
showTitle: !0,
cardFooterAside: "none",
showPersonRoleOrType: !0,
cardCssClass: "personCard",
defaultCardImageIcon: "&#xE7FD;"
}), cardBuilder.buildCards(items, options)
cardLayout: false,
centerText: true,
showTitle: true,
cardFooterAside: 'none',
showPersonRoleOrType: true,
cardCssClass: 'personCard',
defaultCardImageIcon: '&#xE7FD;'
});
cardBuilder.buildCards(items, options);
}
return {
buildPeopleCards: buildPeopleCards
}
};
});
@@ -1,10 +1,7 @@
.card-round:focus>.cardBox-focustransform {
-webkit-transform: scale(1.26, 1.26);
transform: scale(1.26, 1.26)
.card-round:focus > .cardBox-focustransform {
transform: scale(1.26, 1.26);
}
.cardImage-round,
.cardImageContainer-round {
-webkit-border-radius: 1000px;
border-radius: 1000px
}
.cardImageContainer-round, .cardImage-round {
border-radius: 1000px;
}
@@ -1,67 +1,228 @@
define(["events"], function(events) {
"use strict";
define(['events'], function (events) {
'use strict';
// LinkParser
//
// https://github.com/ravisorg/LinkParser
//
// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and
// IPv6, unrecognised TLDs, and more.
//
// This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
// http://creativecommons.org/licenses/by-sa/4.0/
(function () {
// Original URL regex from the Android android.text.util.Linkify function, found here:
// http://stackoverflow.com/a/19696443
//
// However there were problems with it, most probably related to the fact it was
// written in 2007, and it's been highly modified.
//
// 1) I didn't like the fact that it was tied to specific TLDs, since new ones
// are being added all the time it wouldn't be reasonable to expect developer to
// be continually updating their regular expressions.
//
// 2) It didn't allow unicode characters in the domains which are now allowed in
// many languages, (including some IDN TLDs). Again these are constantly being
// added to and it doesn't seem reasonable to hard-code them. Note this ended up
// not being possible in standard JS due to the way it handles multibyte strings.
// It is possible using XRegExp, however a big performance hit results. Disabled
// for now.
//
// 3) It didn't allow for IPv6 hostnames
// IPv6 regex from http://stackoverflow.com/a/17871737
//
// 4) It was very poorly commented
//
// 5) It wasn't as smart as it could have been about what should be part of a
// URL and what should be part of human language.
var protocols = "(?:(?:http|https|rtsp|ftp):\\/\\/)";
var credentials = "(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}" // username (1-64 normal or url escaped characters)
+ "(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?" // followed by optional password (: + 1-25 normal or url escaped characters)
+ "\\@)";
// IPv6 Regex http://forums.intermapper.com/viewtopic.php?t=452
// by Dartware, LLC is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License
// http://intermapper.com/
var ipv6 = "("
+ "(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))"
+ "|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))"
+ "|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))"
+ "|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
+ "|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
+ "|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
+ "|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
+ "|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))"
+ ")(%.+)?";
var ipv4 = "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\."
+ "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\."
+ "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\."
+ "(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])";
// This would have been a lot cleaner if JS RegExp supported conditionals...
var linkRegExpString =
// begin match for protocol / username / password / host
"(?:"
// ============================
// If we have a recognized protocol at the beginning of the URL, we're
// more relaxed about what we accept, because we assume the user wants
// this to be a URL, and we're not accidentally matching human language
+ protocols + "?"
// optional username:password@
+ credentials + "?"
// IP address (both v4 and v6)
+ "(?:"
// IPv6
+ ipv6
// IPv4
+ "|" + ipv4
+ ")"
// end match for protocol / username / password / host
+ ")"
// optional port number
+ "(?:\\:\\d{1,5})?"
// plus optional path and query params (no unicode allowed here?)
+ "(?:"
+ "\\/(?:"
// some characters we'll accept because it's unlikely human language
// would use them after a URL unless they were part of the url
+ "(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])"
+ "|(?:\\%[a-f0-9]{2})"
// some characters are much more likely to be used AFTER a url and
// were not intended to be included in the url itself. Mostly end
// of sentence type things. It's also likely that the URL would
// still work if any of these characters were missing from the end
// because we parsed it incorrectly. For these characters to be accepted
// they must be followed by another character that we're reasonably
// sure is part of the url
+ "|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})))"
+ ")*"
+ "|\\b|\$"
+ ")";
// regex = XRegExp(regex,'gi');
var linkRegExp = RegExp(linkRegExpString, 'gi');
var protocolRegExp = RegExp('^' + protocols, 'i');
// if url doesn't begin with a known protocol, add http by default
function ensureProtocol(url) {
if (!url.match(protocolRegExp)) {
url = "http://" + url;
}
return url;
}
// look for links in the text
var LinkParser = {
parse: function (text) {
var links = [];
var match;
while (match = linkRegExp.exec(text)) {
// console.log(matches);
var txt = match[0];
var pos = match.index;
var len = txt.length;
var url = ensureProtocol(text);
links.push({ 'pos': pos, 'text': txt, 'len': len, 'url': url });
}
return links;
}
};
window.LinkParser = LinkParser;
})();
var cache = {};
function isValidIpAddress(address) {
return 1 == LinkParser.parse(address).length
var links = LinkParser.parse(address);
return links.length == 1;
}
function isLocalIpAddress(address) {
return address = address.toLowerCase(), -1 !== address.indexOf("127.0.0.1") || -1 !== address.indexOf("localhost")
address = address.toLowerCase();
if (address.indexOf('127.0.0.1') !== -1) {
return true;
}
if (address.indexOf('localhost') !== -1) {
return true;
}
return false;
}
function getServerAddress(apiClient) {
var serverAddress = apiClient.serverAddress();
if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) return Promise.resolve(serverAddress);
if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) {
return Promise.resolve(serverAddress);
}
var cachedValue = getCachedValue(serverAddress);
return cachedValue ? Promise.resolve(cachedValue) : apiClient.getEndpointInfo().then(function(endpoint) {
return endpoint.IsInNetwork ? apiClient.getPublicSystemInfo().then(function(info) {
return addToCache(serverAddress, info.LocalAddress), info.LocalAddress
}) : (addToCache(serverAddress, serverAddress), serverAddress)
})
if (cachedValue) {
return Promise.resolve(cachedValue);
}
return apiClient.getEndpointInfo().then(function (endpoint) {
if (endpoint.IsInNetwork) {
return apiClient.getPublicSystemInfo().then(function (info) {
addToCache(serverAddress, info.LocalAddress);
return info.LocalAddress;
});
} else {
addToCache(serverAddress, serverAddress);
return serverAddress;
}
});
}
function clearCache() {
cache = {}
cache = {};
}
function addToCache(key, value) {
cache[key] = {
value: value,
time: (new Date).getTime()
}
time: new Date().getTime()
};
}
function getCachedValue(key) {
var obj = cache[key];
return obj && (new Date).getTime() - obj.time < 18e4 ? obj.value : null
}! function() {
function ensureProtocol(url) {
return url.match(protocolRegExp) || (url = "http://" + url), url
if (obj && (new Date().getTime() - obj.time) < 180000) {
return obj.value;
}
var protocols = "(?:(?:http|https|rtsp|ftp):\\/\\/)",
linkRegExp = RegExp("(?:(?:(?:http|https|rtsp|ftp):\\/\\/)?(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?\\@)?(?:((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?|(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])))(?:\\:\\d{1,5})?(?:\\/(?:(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2}))))*|\\b|$)", "gi"),
protocolRegExp = RegExp("^" + protocols, "i"),
LinkParser = {
parse: function(text) {
for (var match, links = []; match = linkRegExp.exec(text);) {
var txt = match[0],
pos = match.index,
len = txt.length,
url = ensureProtocol(text);
links.push({
pos: pos,
text: txt,
len: len,
url: url
})
}
return links
}
};
window.LinkParser = LinkParser
}();
var cache = {};
return events.on(ConnectionManager, "localusersignedin", clearCache), events.on(ConnectionManager, "localusersignedout", clearCache), {
getServerAddress: getServerAddress
return null;
}
events.on(ConnectionManager, 'localusersignedin', clearCache);
events.on(ConnectionManager, 'localusersignedout', clearCache);
return {
getServerAddress: getServerAddress
};
});
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,12 +1,12 @@
.clearButton {
background: 0 0;
background: transparent;
border: 0 !important;
padding: 0 !important;
cursor: pointer;
outline: 0 !important;
outline: none !important;
color: inherit;
width: 100%;
vertical-align: middle;
font-family: inherit;
font-size: inherit
font-size: inherit;
}
@@ -1,119 +1,287 @@
define(["dialogHelper", "loading", "apphost", "layoutManager", "connectionManager", "appRouter", "globalize", "emby-checkbox", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) {
"use strict";
define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) {
'use strict';
var currentServerId;
function parentWithClass(elem, className) {
for (; !elem.classList || !elem.classList.contains(className);)
if (!(elem = elem.parentNode)) return null;
return elem
while (!elem.classList || !elem.classList.contains(className)) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
}
function onSubmit(e) {
loading.show();
var panel = parentWithClass(this, "dialog"),
collectionId = panel.querySelector("#selectCollectionToAddTo").value,
apiClient = connectionManager.getApiClient(currentServerId);
return collectionId ? addToCollection(apiClient, panel, collectionId) : createCollection(apiClient, panel), e.preventDefault(), !1
var panel = parentWithClass(this, 'dialog');
var collectionId = panel.querySelector('#selectCollectionToAddTo').value;
var apiClient = connectionManager.getApiClient(currentServerId);
if (collectionId) {
addToCollection(apiClient, panel, collectionId);
} else {
createCollection(apiClient, panel);
}
e.preventDefault();
return false;
}
function createCollection(apiClient, dlg) {
var url = apiClient.getUrl("Collections", {
Name: dlg.querySelector("#txtNewCollectionName").value,
IsLocked: !dlg.querySelector("#chkEnableInternetMetadata").checked,
Ids: dlg.querySelector(".fldSelectedItemIds").value || ""
Name: dlg.querySelector('#txtNewCollectionName').value,
IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked,
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
});
apiClient.ajax({
type: "POST",
url: url,
dataType: "json"
}).then(function(result) {
}).then(function (result) {
loading.hide();
var id = result.Id;
dlg.submitted = !0, dialogHelper.close(dlg), redirectToCollection(apiClient, id)
})
dlg.submitted = true;
dialogHelper.close(dlg);
redirectToCollection(apiClient, id);
});
}
function redirectToCollection(apiClient, id) {
appRouter.showItem(id, apiClient.serverId())
appRouter.showItem(id, apiClient.serverId());
}
function addToCollection(apiClient, dlg, id) {
var url = apiClient.getUrl("Collections/" + id + "/Items", {
Ids: dlg.querySelector(".fldSelectedItemIds").value || ""
Ids: dlg.querySelector('.fldSelectedItemIds').value || ''
});
apiClient.ajax({
type: "POST",
url: url
}).then(function() {
loading.hide(), dlg.submitted = !0, dialogHelper.close(dlg), require(["toast"], function(toast) {
toast(globalize.translate("sharedcomponents#MessageItemsAdded"))
})
})
}).then(function () {
loading.hide();
dlg.submitted = true;
dialogHelper.close(dlg);
require(['toast'], function (toast) {
toast(globalize.translate('sharedcomponents#MessageItemsAdded'));
});
});
}
function triggerChange(select) {
select.dispatchEvent(new CustomEvent("change", {}))
select.dispatchEvent(new CustomEvent('change', {}));
}
function populateCollections(panel) {
loading.show();
var select = panel.querySelector("#selectCollectionToAddTo");
panel.querySelector(".newCollectionInfo").classList.add("hide");
var select = panel.querySelector('#selectCollectionToAddTo');
panel.querySelector('.newCollectionInfo').classList.add('hide');
var options = {
Recursive: !0,
IncludeItemTypes: "BoxSet",
SortBy: "SortName",
EnableTotalRecordCount: !1
},
apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function(result) {
var html = "";
html += '<option value="">' + globalize.translate("sharedcomponents#OptionNew") + "</option>", html += result.Items.map(function(i) {
return '<option value="' + i.Id + '">' + i.Name + "</option>"
}), select.innerHTML = html, select.value = "", triggerChange(select), loading.hide()
})
Recursive: true,
IncludeItemTypes: "BoxSet",
SortBy: "SortName",
EnableTotalRecordCount: false
};
var apiClient = connectionManager.getApiClient(currentServerId);
apiClient.getItems(apiClient.getCurrentUserId(), options).then(function (result) {
var html = '';
html += '<option value="">' + globalize.translate('sharedcomponents#OptionNew') + '</option>';
html += result.Items.map(function (i) {
return '<option value="' + i.Id + '">' + i.Name + '</option>';
});
select.innerHTML = html;
select.value = '';
triggerChange(select);
loading.hide();
});
}
function getEditorHtml() {
var html = "";
return html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">', html += '<div class="dialogContentInner dialog-content-centered">', html += '<form class="newCollectionForm" style="margin:auto;">', html += "<div>", html += globalize.translate("sharedcomponents#NewCollectionHelp"), html += "</div>", html += '<div class="fldSelectCollection">', html += "<br/>", html += "<br/>", html += '<div class="selectContainer">', html += '<select is="emby-select" label="' + globalize.translate("sharedcomponents#LabelCollection") + '" id="selectCollectionToAddTo" autofocus></select>', html += "</div>", html += "</div>", html += '<div class="newCollectionInfo">', html += '<div class="inputContainer">', html += '<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="' + globalize.translate("sharedcomponents#LabelName") + '" />', html += '<div class="fieldDescription">' + globalize.translate("sharedcomponents#NewCollectionNameExample") + "</div>", html += "</div>", html += '<label class="checkboxContainer">', html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />', html += "<span>" + globalize.translate("sharedcomponents#SearchForCollectionInternetMetadata") + "</span>", html += "</label>", html += "</div>", html += '<div class="formDialogFooter">', html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate("sharedcomponents#ButtonOk") + "</button>", html += "</div>", html += '<input type="hidden" class="fldSelectedItemIds" />', html += "</form>", html += "</div>", html += "</div>"
var html = '';
html += '<div class="formDialogContent smoothScrollY" style="padding-top:2em;">';
html += '<div class="dialogContentInner dialog-content-centered">';
html += '<form class="newCollectionForm" style="margin:auto;">';
html += '<div>';
html += globalize.translate('sharedcomponents#NewCollectionHelp');
html += '</div>';
html += '<div class="fldSelectCollection">';
html += '<br/>';
html += '<br/>';
html += '<div class="selectContainer">';
html += '<select is="emby-select" label="' + globalize.translate('sharedcomponents#LabelCollection') + '" id="selectCollectionToAddTo" autofocus></select>';
html += '</div>';
html += '</div>';
html += '<div class="newCollectionInfo">';
html += '<div class="inputContainer">';
html += '<input is="emby-input" type="text" id="txtNewCollectionName" required="required" label="' + globalize.translate('sharedcomponents#LabelName') + '" />';
html += '<div class="fieldDescription">' + globalize.translate('sharedcomponents#NewCollectionNameExample') + '</div>';
html += '</div>';
html += '<label class="checkboxContainer">';
html += '<input is="emby-checkbox" type="checkbox" id="chkEnableInternetMetadata" />';
html += '<span>' + globalize.translate('sharedcomponents#SearchForCollectionInternetMetadata') + '</span>';
html += '</label>';
// newCollectionInfo
html += '</div>';
html += '<div class="formDialogFooter">';
html += '<button is="emby-button" type="submit" class="raised btnSubmit block formDialogFooterItem button-submit">' + globalize.translate('sharedcomponents#ButtonOk') + '</button>';
html += '</div>';
html += '<input type="hidden" class="fldSelectedItemIds" />';
html += '</form>';
html += '</div>';
html += '</div>';
return html;
}
function initEditor(content, items) {
if (content.querySelector("#selectCollectionToAddTo").addEventListener("change", function() {
this.value ? (content.querySelector(".newCollectionInfo").classList.add("hide"), content.querySelector("#txtNewCollectionName").removeAttribute("required")) : (content.querySelector(".newCollectionInfo").classList.remove("hide"), content.querySelector("#txtNewCollectionName").setAttribute("required", "required"))
}), content.querySelector("form").addEventListener("submit", onSubmit), content.querySelector(".fldSelectedItemIds", content).value = items.join(","), items.length) content.querySelector(".fldSelectCollection").classList.remove("hide"), populateCollections(content);
else {
content.querySelector(".fldSelectCollection").classList.add("hide");
var selectCollectionToAddTo = content.querySelector("#selectCollectionToAddTo");
selectCollectionToAddTo.innerHTML = "", selectCollectionToAddTo.value = "", triggerChange(selectCollectionToAddTo)
content.querySelector('#selectCollectionToAddTo').addEventListener('change', function () {
if (this.value) {
content.querySelector('.newCollectionInfo').classList.add('hide');
content.querySelector('#txtNewCollectionName').removeAttribute('required');
} else {
content.querySelector('.newCollectionInfo').classList.remove('hide');
content.querySelector('#txtNewCollectionName').setAttribute('required', 'required');
}
});
content.querySelector('form').addEventListener('submit', onSubmit);
content.querySelector('.fldSelectedItemIds', content).value = items.join(',');
if (items.length) {
content.querySelector('.fldSelectCollection').classList.remove('hide');
populateCollections(content);
} else {
content.querySelector('.fldSelectCollection').classList.add('hide');
var selectCollectionToAddTo = content.querySelector('#selectCollectionToAddTo');
selectCollectionToAddTo.innerHTML = '';
selectCollectionToAddTo.value = '';
triggerChange(selectCollectionToAddTo);
}
}
function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) {
var fn = on ? "on" : "off";
scrollHelper.centerFocus[fn](elem, horiz)
})
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function CollectionEditor() {}
var currentServerId;
return CollectionEditor.prototype.show = function(options) {
function CollectionEditor() {
}
CollectionEditor.prototype.show = function (options) {
var items = options.items || {};
currentServerId = options.serverId;
var dialogOptions = {
removeOnClose: !0,
scrollY: !1
removeOnClose: true,
scrollY: false
};
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small";
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog");
var html = "",
title = items.length ? globalize.translate("sharedcomponents#HeaderAddToCollection") : globalize.translate("sharedcomponents#NewCollection");
return html += '<div class="formDialogHeader">', html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>', html += '<h3 class="formDialogHeaderTitle">', html += title, html += "</h3>", appHost.supports("externallinks") && (html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate("sharedcomponents#Help") + '"><i class="md-icon">&#xE88E;</i><span style="margin-left:.25em;">' + globalize.translate("sharedcomponents#Help") + "</span></a>"), html += "</div>", html += getEditorHtml(), dlg.innerHTML = html, initEditor(dlg, items), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg)
}), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0), dialogHelper.open(dlg).then(function() {
return layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), dlg.submitted ? Promise.resolve() : Promise.reject()
})
}, CollectionEditor
dlg.classList.add('formDialog');
var html = '';
var title = items.length ? globalize.translate('sharedcomponents#HeaderAddToCollection') : globalize.translate('sharedcomponents#NewCollection');
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>';
html += '<h3 class="formDialogHeaderTitle">';
html += title;
html += '</h3>';
if (appHost.supports('externallinks')) {
html += '<a is="emby-linkbutton" class="button-link btnHelp flex align-items-center" href="https://github.com/MediaBrowser/Wiki/wiki/Collections" target="_blank" style="margin-left:auto;margin-right:.5em;padding:.25em;" title="' + globalize.translate('sharedcomponents#Help') + '"><i class="md-icon">&#xE88E;</i><span style="margin-left:.25em;">' + globalize.translate('sharedcomponents#Help') + '</span></a>';
}
html += '</div>';
html += getEditorHtml();
dlg.innerHTML = html;
initEditor(dlg, items);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
return dialogHelper.open(dlg).then(function () {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (dlg.submitted) {
return Promise.resolve();
}
return Promise.reject();
});
};
return CollectionEditor;
});
+37 -19
View File
@@ -1,22 +1,40 @@
define(["dialog", "globalize"], function(dialog, globalize) {
"use strict";
return function(text, title) {
define(['dialog', 'globalize'], function (dialog, globalize) {
'use strict';
return function (text, title) {
var options;
options = "string" == typeof text ? {
title: title,
text: text
} : text;
if (typeof text === 'string') {
options = {
title: title,
text: text
};
} else {
options = text;
}
var items = [];
return items.push({
name: options.cancelText || globalize.translate("sharedcomponents#ButtonCancel"),
id: "cancel",
type: "cancel" === options.primary ? "submit" : "cancel"
}), items.push({
name: options.confirmText || globalize.translate("sharedcomponents#ButtonOk"),
id: "ok",
type: "cancel" === options.primary ? "cancel" : "submit"
}), options.buttons = items, dialog(options).then(function(result) {
return "ok" === result ? Promise.resolve() : Promise.reject()
})
}
items.push({
name: options.cancelText || globalize.translate('sharedcomponents#ButtonCancel'),
id: 'cancel',
type: options.primary === 'cancel' ? 'submit' : 'cancel'
});
items.push({
name: options.confirmText || globalize.translate('sharedcomponents#ButtonOk'),
id: 'ok',
type: options.primary === 'cancel' ? 'cancel' : 'submit'
});
options.buttons = items;
return dialog(options).then(function (result) {
if (result === 'ok') {
return Promise.resolve();
}
return Promise.reject();
});
};
});
@@ -1,15 +1,27 @@
define([], function() {
"use strict";
define([], function () {
'use strict';
function replaceAll(str, find, replace) {
return str.split(find).join(replace)
}
return function(options) {
"string" == typeof options && (options = {
title: "",
text: options
});
var text = replaceAll(options.text || "", "<br/>", "\n");
return confirm(text) ? Promise.resolve() : Promise.reject()
return str.split(find).join(replace);
}
return function (options) {
if (typeof options === 'string') {
options = {
title: '',
text: options
};
}
var text = replaceAll(options.text || '', '<br/>', '\n');
var result = confirm(text);
if (result) {
return Promise.resolve();
} else {
return Promise.reject();
}
};
});
+232 -73
View File
@@ -1,113 +1,272 @@
define(["globalize"], function(globalize) {
"use strict";
define(['globalize'], function (globalize) {
'use strict';
function parseISO8601Date(s, toLocal) {
var re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/,
d = s.match(re);
if (!d) throw "Couldn't parse ISO 8601 date string '" + s + "'";
// parenthese matches:
// year month day hours minutes seconds
// dotmilliseconds
// tzstring plusminus hours minutes
var re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/;
var d = s.match(re);
// "2010-12-07T11:00:00.000-09:00" parses to:
// ["2010-12-07T11:00:00.000-09:00", "2010", "12", "07", "11",
// "00", "00", ".000", "-09:00", "-", "09", "00"]
// "2010-12-07T11:00:00.000Z" parses to:
// ["2010-12-07T11:00:00.000Z", "2010", "12", "07", "11",
// "00", "00", ".000", "Z", undefined, undefined, undefined]
if (!d) {
throw "Couldn't parse ISO 8601 date string '" + s + "'";
}
// parse strings, leading zeros into proper ints
var a = [1, 2, 3, 4, 5, 6, 10, 11];
for (var i in a) d[a[i]] = parseInt(d[a[i]], 10);
for (var i in a) {
d[a[i]] = parseInt(d[a[i]], 10);
}
d[7] = parseFloat(d[7]);
// Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]])
// note that month is 0-11, not 1-12
// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC
var ms = Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6]);
if (d[7] > 0 && (ms += Math.round(1e3 * d[7])), "Z" !== d[8] && d[10]) {
var offset = 60 * d[10] * 60 * 1e3;
d[11] && (offset += 60 * d[11] * 1e3), "-" === d[9] ? ms -= offset : ms += offset
} else !1 === toLocal && (ms += 6e4 * (new Date).getTimezoneOffset());
return new Date(ms)
// if there are milliseconds, add them
if (d[7] > 0) {
ms += Math.round(d[7] * 1000);
}
// if there's a timezone, calculate it
if (d[8] !== "Z" && d[10]) {
var offset = d[10] * 60 * 60 * 1000;
if (d[11]) {
offset += d[11] * 60 * 1000;
}
if (d[9] === "-") {
ms -= offset;
} else {
ms += offset;
}
} else if (toLocal === false) {
ms += new Date().getTimezoneOffset() * 60000;
}
return new Date(ms);
}
function getDisplayRunningTime(ticks) {
var parts = [],
hours = ticks / 36e9;
hours = Math.floor(hours), hours && parts.push(hours), ticks -= 36e9 * hours;
var minutes = ticks / 6e8;
minutes = Math.floor(minutes), ticks -= 6e8 * minutes, minutes < 10 && hours && (minutes = "0" + minutes), parts.push(minutes);
var seconds = ticks / 1e7;
return seconds = Math.floor(seconds), seconds < 10 && (seconds = "0" + seconds), parts.push(seconds), parts.join(":")
var ticksPerHour = 36000000000;
var ticksPerMinute = 600000000;
var ticksPerSecond = 10000000;
var parts = [];
var hours = ticks / ticksPerHour;
hours = Math.floor(hours);
if (hours) {
parts.push(hours);
}
ticks -= (hours * ticksPerHour);
var minutes = ticks / ticksPerMinute;
minutes = Math.floor(minutes);
ticks -= (minutes * ticksPerMinute);
if (minutes < 10 && hours) {
minutes = '0' + minutes;
}
parts.push(minutes);
var seconds = ticks / ticksPerSecond;
seconds = Math.floor(seconds);
if (seconds < 10) {
seconds = '0' + seconds;
}
parts.push(seconds);
return parts.join(':');
}
var toLocaleTimeStringSupportsLocales = function () {
try {
new Date().toLocaleTimeString('i');
} catch (e) {
return e.name === 'RangeError';
}
return false;
}();
function getOptionList(options) {
var list = [];
for (var i in options) list.push({
name: i,
value: options[i]
});
return list
for (var i in options) {
list.push({
name: i,
value: options[i]
});
}
return list;
}
function toLocaleString(date, options) {
if (!date) throw new Error("date cannot be null");
if (options = options || {}, toLocaleTimeStringSupportsLocales) {
var currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) return date.toLocaleString(currentLocale, options)
if (!date) {
throw new Error('date cannot be null');
}
return date.toLocaleString()
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
var currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleString(currentLocale, options);
}
}
return date.toLocaleString();
}
function toLocaleDateString(date, options) {
if (!date) throw new Error("date cannot be null");
if (options = options || {}, toLocaleTimeStringSupportsLocales) {
if (!date) {
throw new Error('date cannot be null');
}
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
var currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) return date.toLocaleDateString(currentLocale, options)
if (currentLocale) {
return date.toLocaleDateString(currentLocale, options);
}
}
// This is essentially a hard-coded polyfill
var optionList = getOptionList(options);
if (1 === optionList.length && "weekday" === optionList[0].name) {
if (optionList.length === 1 && optionList[0].name === 'weekday') {
var weekday = [];
return weekday[0] = "Sun", weekday[1] = "Mon", weekday[2] = "Tue", weekday[3] = "Wed", weekday[4] = "Thu", weekday[5] = "Fri", weekday[6] = "Sat", weekday[date.getDay()]
weekday[0] = "Sun";
weekday[1] = "Mon";
weekday[2] = "Tue";
weekday[3] = "Wed";
weekday[4] = "Thu";
weekday[5] = "Fri";
weekday[6] = "Sat";
return weekday[date.getDay()];
}
return date.toLocaleDateString()
return date.toLocaleDateString();
}
function toLocaleTimeString(date, options) {
if (!date) throw new Error("date cannot be null");
if (options = options || {}, toLocaleTimeStringSupportsLocales) {
var currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) return date.toLocaleTimeString(currentLocale, options)
if (!date) {
throw new Error('date cannot be null');
}
return date.toLocaleTimeString()
options = options || {};
if (toLocaleTimeStringSupportsLocales) {
var currentLocale = globalize.getCurrentDateTimeLocale();
if (currentLocale) {
return date.toLocaleTimeString(currentLocale, options);
}
}
return date.toLocaleTimeString();
}
function getDisplayTime(date) {
if (!date) throw new Error("date cannot be null");
if ("string" === (typeof date).toString().toLowerCase()) try {
date = parseISO8601Date(date, !0)
} catch (err) {
return date
if (!date) {
throw new Error('date cannot be null');
}
if (toLocaleTimeStringSupportsLocales) return toLocaleTimeString(date, {
hour: "numeric",
minute: "2-digit"
});
var time = toLocaleTimeString(date),
timeLower = time.toLowerCase();
if (-1 !== timeLower.indexOf("am") || -1 !== timeLower.indexOf("pm")) {
if ((typeof date).toString().toLowerCase() === 'string') {
try {
date = parseISO8601Date(date, true);
} catch (err) {
return date;
}
}
if (toLocaleTimeStringSupportsLocales) {
return toLocaleTimeString(date, {
hour: 'numeric',
minute: '2-digit'
});
}
var time = toLocaleTimeString(date);
var timeLower = time.toLowerCase();
if (timeLower.indexOf('am') !== -1 || timeLower.indexOf('pm') !== -1) {
time = timeLower;
var hour = date.getHours() % 12,
suffix = date.getHours() > 11 ? "pm" : "am";
hour || (hour = 12);
var hour = date.getHours() % 12;
var suffix = date.getHours() > 11 ? 'pm' : 'am';
if (!hour) {
hour = 12;
}
var minutes = date.getMinutes();
minutes < 10 && (minutes = "0" + minutes), minutes = ":" + minutes, time = hour + minutes + suffix
if (minutes < 10) {
minutes = '0' + minutes;
}
minutes = ':' + minutes;
time = hour + minutes + suffix;
} else {
var timeParts = time.split(":");
timeParts.length > 2 && (timeParts.length = 2, time = timeParts.join(":"))
var timeParts = time.split(':');
// Trim off seconds
if (timeParts.length > 2) {
// setting to 2 also handles '21:00:28 GMT+9:30'
timeParts.length = 2;
time = timeParts.join(':');
}
}
return time
return time;
}
function isRelativeDay(date, offsetInDays) {
if (!date) throw new Error("date cannot be null");
var yesterday = new Date,
day = yesterday.getDate() + offsetInDays;
return yesterday.setDate(day), date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day
}
var toLocaleTimeStringSupportsLocales = function() {
try {
(new Date).toLocaleTimeString("i")
} catch (e) {
return "RangeError" === e.name
if (!date) {
throw new Error('date cannot be null');
}
return !1
}();
var yesterday = new Date();
var day = yesterday.getDate() + offsetInDays;
yesterday.setDate(day); // automatically adjusts month/year appropriately
return date.getFullYear() === yesterday.getFullYear() && date.getMonth() === yesterday.getMonth() && date.getDate() === day;
}
return {
parseISO8601Date: parseISO8601Date,
getDisplayRunningTime: getDisplayRunningTime,
@@ -116,8 +275,8 @@ define(["globalize"], function(globalize) {
getDisplayTime: getDisplayTime,
isRelativeDay: isRelativeDay,
toLocaleTimeString: toLocaleTimeString,
supportsLocalization: function() {
return toLocaleTimeStringSupportsLocales
supportsLocalization: function () {
return toLocaleTimeStringSupportsLocales;
}
}
};
});
+44 -26
View File
@@ -1,39 +1,57 @@
define(["connectionManager", "confirm", "appRouter", "globalize"], function(connectionManager, confirm, appRouter, globalize) {
"use strict";
define(['connectionManager', 'confirm', 'appRouter', 'globalize'], function (connectionManager, confirm, appRouter, globalize) {
'use strict';
function alertText(options) {
return new Promise(function(resolve, reject) {
require(["alert"], function(alert) {
alert(options).then(resolve, resolve)
})
})
return new Promise(function (resolve, reject) {
require(['alert'], function (alert) {
alert(options).then(resolve, resolve);
});
});
}
function deleteItem(options) {
var item = options.item,
itemId = item.Id,
parentId = item.SeasonId || item.SeriesId || item.ParentId,
serverId = item.ServerId,
msg = globalize.translate("sharedcomponents#ConfirmDeleteItem"),
title = globalize.translate("sharedcomponents#HeaderDeleteItem"),
apiClient = connectionManager.getApiClient(item.ServerId);
var item = options.item;
var itemId = item.Id;
var parentId = item.SeasonId || item.SeriesId || item.ParentId;
var serverId = item.ServerId;
var msg = globalize.translate('sharedcomponents#ConfirmDeleteItem');
var title = globalize.translate('sharedcomponents#HeaderDeleteItem');
var apiClient = connectionManager.getApiClient(item.ServerId);
return confirm({
title: title,
text: msg,
confirmText: globalize.translate("sharedcomponents#Delete"),
primary: "cancel"
}).then(function() {
return apiClient.deleteItem(itemId).then(function() {
options.navigate && (parentId ? appRouter.showItem(parentId, serverId) : appRouter.goHome())
}, function(err) {
var result = function() {
return Promise.reject(err)
confirmText: globalize.translate('sharedcomponents#Delete'),
primary: 'cancel'
}).then(function () {
return apiClient.deleteItem(itemId).then(function () {
if (options.navigate) {
if (parentId) {
appRouter.showItem(parentId, serverId);
} else {
appRouter.goHome();
}
}
}, function (err) {
var result = function () {
return Promise.reject(err);
};
return alertText(globalize.translate("sharedcomponents#ErrorDeletingItem")).then(result, result)
})
})
return alertText(globalize.translate('sharedcomponents#ErrorDeletingItem')).then(result, result);
});
});
}
return {
deleteItem: deleteItem
}
};
});
+126 -39
View File
@@ -1,46 +1,133 @@
define(["dialogHelper", "dom", "layoutManager", "scrollHelper", "globalize", "require", "material-icons", "emby-button", "paper-icon-button-light", "emby-input", "formDialogStyle", "flexStyles"], function(dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
"use strict";
define(['dialogHelper', 'dom', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle', 'flexStyles'], function (dialogHelper, dom, layoutManager, scrollHelper, globalize, require) {
'use strict';
function showDialog(options, template) {
function onButtonClick() {
dialogResult = this.getAttribute("data-id"), dialogHelper.close(dlg)
}
var dialogOptions = {
removeOnClose: !0,
scrollY: !1
},
enableTvLayout = layoutManager.tv;
enableTvLayout && (dialogOptions.size = "fullscreen");
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateHtml(template, "sharedcomponents"), dlg.classList.add("align-items-center"), dlg.classList.add("justify-content-center");
var formDialogContent = dlg.querySelector(".formDialogContent");
formDialogContent.classList.add("no-grow"), enableTvLayout ? (formDialogContent.style["max-width"] = "50%", formDialogContent.style["max-height"] = "60%", scrollHelper.centerFocus.on(formDialogContent, !1)) : (formDialogContent.style.maxWidth = Math.min(150 * options.buttons.length + 200, dom.getWindowSize().innerWidth - 50) + "px", dlg.classList.add("dialog-fullscreen-lowres")), options.title ? dlg.querySelector(".formDialogHeaderTitle").innerHTML = options.title || "" : dlg.querySelector(".formDialogHeaderTitle").classList.add("hide");
var displayText = options.html || options.text || "";
dlg.querySelector(".text").innerHTML = displayText, displayText || dlg.querySelector(".dialogContentInner").classList.add("hide");
var i, length, html = "",
hasDescriptions = !1;
for (i = 0, length = options.buttons.length; i < length; i++) {
var item = options.buttons[i],
autoFocus = 0 === i ? " autofocus" : "",
buttonClass = "btnOption raised formDialogFooterItem formDialogFooterItem-autosize";
item.type && (buttonClass += " button-" + item.type), item.description && (hasDescriptions = !0), hasDescriptions && (buttonClass += " formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom"), html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + ">" + item.name + "</button>", item.description && (html += '<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">' + item.description + "</div>")
removeOnClose: true,
scrollY: false
};
var enableTvLayout = layoutManager.tv;
if (enableTvLayout) {
dialogOptions.size = 'fullscreen';
}
dlg.querySelector(".formDialogFooter").innerHTML = html, hasDescriptions && dlg.querySelector(".formDialogFooter").classList.add("formDialogFooter-vertical");
var dialogResult, buttons = dlg.querySelectorAll(".btnOption");
for (i = 0, length = buttons.length; i < length; i++) buttons[i].addEventListener("click", onButtonClick);
return dialogHelper.open(dlg).then(function() {
return enableTvLayout && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), dialogResult || Promise.reject()
})
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateHtml(template, 'sharedcomponents');
dlg.classList.add('align-items-center');
dlg.classList.add('justify-content-center');
var formDialogContent = dlg.querySelector('.formDialogContent');
formDialogContent.classList.add('no-grow');
if (enableTvLayout) {
formDialogContent.style['max-width'] = '50%';
formDialogContent.style['max-height'] = '60%';
scrollHelper.centerFocus.on(formDialogContent, false);
} else {
formDialogContent.style.maxWidth = (Math.min((options.buttons.length * 150) + 200, dom.getWindowSize().innerWidth - 50)) + 'px';
dlg.classList.add('dialog-fullscreen-lowres');
}
//dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
// dialogHelper.close(dlg);
//});
if (options.title) {
dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || '';
} else {
dlg.querySelector('.formDialogHeaderTitle').classList.add('hide');
}
var displayText = options.html || options.text || '';
dlg.querySelector('.text').innerHTML = displayText;
if (!displayText) {
dlg.querySelector('.dialogContentInner').classList.add('hide');
}
var i, length;
var html = '';
var hasDescriptions = false;
for (i = 0, length = options.buttons.length; i < length; i++) {
var item = options.buttons[i];
var autoFocus = i === 0 ? ' autofocus' : '';
var buttonClass = 'btnOption raised formDialogFooterItem formDialogFooterItem-autosize';
if (item.type) {
buttonClass += ' button-' + item.type;
}
if (item.description) {
hasDescriptions = true;
}
if (hasDescriptions) {
buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom';
}
html += '<button is="emby-button" type="button" class="' + buttonClass + '" data-id="' + item.id + '"' + autoFocus + '>' + item.name + '</button>';
if (item.description) {
html += '<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">' + item.description + '</div>';
}
}
dlg.querySelector('.formDialogFooter').innerHTML = html;
if (hasDescriptions) {
dlg.querySelector('.formDialogFooter').classList.add('formDialogFooter-vertical');
}
var dialogResult;
function onButtonClick() {
dialogResult = this.getAttribute('data-id');
dialogHelper.close(dlg);
}
var buttons = dlg.querySelectorAll('.btnOption');
for (i = 0, length = buttons.length; i < length; i++) {
buttons[i].addEventListener('click', onButtonClick);
}
return dialogHelper.open(dlg).then(function () {
if (enableTvLayout) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
}
if (dialogResult) {
return dialogResult;
} else {
return Promise.reject();
}
});
}
return function(text, title) {
return function (text, title) {
var options;
return options = "string" == typeof text ? {
title: title,
text: text
} : text, new Promise(function(resolve, reject) {
require(["text!./dialog.template.html"], function(template) {
showDialog(options, template).then(resolve, reject)
})
})
}
if (typeof text === 'string') {
options = {
title: title,
text: text
};
} else {
options = text;
}
return new Promise(function (resolve, reject) {
require(['text!./dialog.template.html'], function (template) {
showDialog(options, template).then(resolve, reject);
});
});
};
});
@@ -1,12 +1,6 @@
.dialogContainer {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
position: fixed;
top: 0;
@@ -16,234 +10,148 @@
z-index: 999999 !important;
contain: strict;
overflow: hidden;
overscroll-behavior: contain
overscroll-behavior: contain;
}
.dialog {
margin: 0;
-webkit-border-radius: .2em;
border-radius: .2em;
-webkit-font-smoothing: antialiased;
border: 0;
padding: 0;
will-change: transform, opacity;
/* Strict does not work well with actionsheet */
contain: style paint;
-webkit-box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12), 0 8px 10px -5px rgba(0, 0, 0, .4);
box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12), 0 8px 10px -5px rgba(0, 0, 0, .4)
box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.4);
}
.dialog-fixedSize {
-webkit-border-radius: 0;
border-radius: 0;
max-height: none;
max-width: none;
contain: layout style paint
contain: layout style paint;
}
.dialog-fullscreen {
/* Needed due to formDialog style */
position: fixed !important;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: 0;
-webkit-box-shadow: none;
box-shadow: none
}
@-webkit-keyframes scaledown {
from {
opacity: 1;
-webkit-transform: none;
transform: none
}
to {
opacity: 0;
-webkit-transform: scale(.5);
transform: scale(.5)
}
box-shadow: none;
}
@keyframes scaledown {
from {
opacity: 1;
-webkit-transform: none;
transform: none
transform: none;
}
to {
opacity: 0;
-webkit-transform: scale(.5);
transform: scale(.5)
}
}
@-webkit-keyframes scaleup {
from {
-webkit-transform: scale(.5);
transform: scale(.5);
opacity: 0
}
to {
-webkit-transform: none;
transform: none;
opacity: 1
}
}
@keyframes scaleup {
from {
-webkit-transform: scale(.5);
transform: scale(.5);
opacity: 0
opacity: 0;
}
to {
-webkit-transform: none;
transform: none;
opacity: 1
}
}
@-webkit-keyframes fadein {
from {
opacity: 0
}
to {
opacity: 1
opacity: 1;
}
}
@keyframes fadein {
from {
opacity: 0
}
to {
opacity: 1
}
}
@-webkit-keyframes fadeout {
from {
opacity: 1
}
to {
opacity: 0
}
}
@keyframes fadeout {
from {
opacity: 1
}
to {
opacity: 0
}
}
@-webkit-keyframes slideup {
from {
opacity: 0;
-webkit-transform: translate3d(0, 30%, 0);
transform: translate3d(0, 30%, 0)
}
to {
opacity: 1;
-webkit-transform: none;
transform: none
}
}
@keyframes fadeout {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes slideup {
from {
opacity: 0;
-webkit-transform: translate3d(0, 30%, 0);
transform: translate3d(0, 30%, 0)
transform: translate3d(0, 30%, 0);
}
to {
opacity: 1;
-webkit-transform: none;
transform: none
}
}
@-webkit-keyframes slidedown {
from {
opacity: 1;
-webkit-transform: none;
transform: none
}
to {
opacity: 0;
-webkit-transform: translate3d(0, 20%, 0);
transform: translate3d(0, 20%, 0)
transform: none;
}
}
@keyframes slidedown {
from {
opacity: 1;
-webkit-transform: none;
transform: none
transform: none;
}
to {
opacity: 0;
-webkit-transform: translate3d(0, 20%, 0);
transform: translate3d(0, 20%, 0)
transform: translate3d(0, 20%, 0);
}
}
@media all and (max-width:80em),
all and (max-height:45em) {
@media all and (max-width: 80em), all and (max-height: 45em) {
.dialog-fixedSize,
.dialog-fullscreen-lowres {
.dialog-fixedSize, .dialog-fullscreen-lowres {
position: fixed !important;
top: 0 !important;
bottom: 0 !important;
left: 0 !important;
right: 0 !important;
margin: 0 !important;
-webkit-box-shadow: none;
box-shadow: none
box-shadow: none;
}
}
@media all and (min-width:80em) and (min-height:45em) {
@media all and (min-width: 80em) and (min-height: 45em) {
.dialog-medium {
width: 80%;
height: 80%
height: 80%;
}
.dialog-medium-tall {
width: 80%;
height: 90%
height: 90%;
}
.dialog-small {
width: 60%;
height: 80%
height: 80%;
}
.dialog-fullscreen-border {
width: 90%;
height: 90%
height: 90%;
}
}
.noScroll {
overflow-x: hidden !important;
overflow-y: hidden !important
overflow-y: hidden !important;
}
.dialogBackdrop {
@@ -256,12 +164,10 @@ all and (max-height:45em) {
right: 0 !important;
margin: 0 !important;
z-index: 999999 !important;
-webkit-transition: opacity ease-out .2s;
-o-transition: opacity ease-out .2s;
transition: opacity ease-out .2s;
will-change: opacity
transition: opacity ease-out 0.2s;
will-change: opacity;
}
.dialogBackdropOpened {
opacity: .5
}
opacity: .5;
}
@@ -1,225 +1,486 @@
define(["appRouter", "focusManager", "browser", "layoutManager", "inputManager", "dom", "css!./dialoghelper.css", "scrollStyles"], function(appRouter, focusManager, browser, layoutManager, inputManager, dom) {
"use strict";
define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', 'dom', 'css!./dialoghelper.css', 'scrollStyles'], function (appRouter, focusManager, browser, layoutManager, inputManager, dom) {
'use strict';
var globalOnOpenCallback;
function enableAnimation() {
return !browser.tv && browser.supportsCssAnimation()
// too slow
if (browser.tv) {
return false;
}
return browser.supportsCssAnimation();
}
function removeCenterFocus(dlg) {
layoutManager.tv && (dlg.classList.contains("scrollX") ? centerFocus(dlg, !0, !1) : dlg.classList.contains("smoothScrollY") && centerFocus(dlg, !1, !1))
if (layoutManager.tv) {
if (dlg.classList.contains('scrollX')) {
centerFocus(dlg, true, false);
}
else if (dlg.classList.contains('smoothScrollY')) {
centerFocus(dlg, false, false);
}
}
}
function tryRemoveElement(elem) {
var parentNode = elem.parentNode;
if (parentNode) try {
parentNode.removeChild(elem)
} catch (err) {
console.log("Error removing dialog element: " + err)
if (parentNode) {
// Seeing crashes in edge webview
try {
parentNode.removeChild(elem);
} catch (err) {
console.log('Error removing dialog element: ' + err);
}
}
}
function DialogHashHandler(dlg, hash, resolve) {
var self = this;
self.originalUrl = window.location.href;
var activeElement = document.activeElement;
var removeScrollLockOnClose = false;
function onHashChange(e) {
var isBack = self.originalUrl === window.location.href;
!isBack && isOpened(dlg) || window.removeEventListener("popstate", onHashChange), isBack && (self.closedByBack = !0, closeDialog(dlg))
if (isBack || !isOpened(dlg)) {
window.removeEventListener('popstate', onHashChange);
}
if (isBack) {
self.closedByBack = true;
closeDialog(dlg);
}
}
function onBackCommand(e) {
"back" === e.detail.command && (self.closedByBack = !0, e.preventDefault(), e.stopPropagation(), closeDialog(dlg))
if (e.detail.command === 'back') {
self.closedByBack = true;
e.preventDefault();
e.stopPropagation();
closeDialog(dlg);
}
}
function onDialogClosed() {
if (isHistoryEnabled(dlg) || inputManager.off(dlg, onBackCommand), window.removeEventListener("popstate", onHashChange), removeBackdrop(dlg), dlg.classList.remove("opened"), removeScrollLockOnClose && document.body.classList.remove("noScroll"), !self.closedByBack && isHistoryEnabled(dlg)) {
(history.state || {}).dialogId === hash && history.back()
if (!isHistoryEnabled(dlg)) {
inputManager.off(dlg, onBackCommand);
}
if (layoutManager.tv && focusManager.focus(activeElement), "false" !== dlg.getAttribute("data-removeonclose")) {
window.removeEventListener('popstate', onHashChange);
removeBackdrop(dlg);
dlg.classList.remove('opened');
if (removeScrollLockOnClose) {
document.body.classList.remove('noScroll');
}
if (!self.closedByBack && isHistoryEnabled(dlg)) {
var state = history.state || {};
if (state.dialogId === hash) {
history.back();
}
}
if (layoutManager.tv) {
focusManager.focus(activeElement);
}
if (dlg.getAttribute('data-removeonclose') !== 'false') {
removeCenterFocus(dlg);
var dialogContainer = dlg.dialogContainer;
dialogContainer ? (tryRemoveElement(dialogContainer), dlg.dialogContainer = null) : tryRemoveElement(dlg)
if (dialogContainer) {
tryRemoveElement(dialogContainer);
dlg.dialogContainer = null;
} else {
tryRemoveElement(dlg);
}
}
setTimeout(function() {
//resolve();
// if we just called history.back(), then use a timeout to allow the history events to fire first
setTimeout(function () {
resolve({
element: dlg,
closedByBack: self.closedByBack
})
}, 1)
});
}, 1);
}
dlg.addEventListener('close', onDialogClosed);
var center = !dlg.classList.contains('dialog-fixedSize');
if (center) {
dlg.classList.add('centeredDialog');
}
dlg.classList.remove('hide');
addBackdropOverlay(dlg);
dlg.classList.add('opened');
dlg.dispatchEvent(new CustomEvent('open', {
bubbles: false,
cancelable: false
}));
if (dlg.getAttribute('data-lockscroll') === 'true' && !document.body.classList.contains('noScroll')) {
document.body.classList.add('noScroll');
removeScrollLockOnClose = true;
}
animateDialogOpen(dlg);
if (isHistoryEnabled(dlg)) {
appRouter.pushState({ dialogId: hash }, "Dialog", '#' + hash);
window.addEventListener('popstate', onHashChange);
} else {
inputManager.on(dlg, onBackCommand);
}
var self = this;
self.originalUrl = window.location.href;
var activeElement = document.activeElement,
removeScrollLockOnClose = !1;
dlg.addEventListener("close", onDialogClosed), !dlg.classList.contains("dialog-fixedSize") && dlg.classList.add("centeredDialog"), dlg.classList.remove("hide"), addBackdropOverlay(dlg), dlg.classList.add("opened"), dlg.dispatchEvent(new CustomEvent("open", {
bubbles: !1,
cancelable: !1
})), "true" !== dlg.getAttribute("data-lockscroll") || document.body.classList.contains("noScroll") || (document.body.classList.add("noScroll"), removeScrollLockOnClose = !0), animateDialogOpen(dlg), isHistoryEnabled(dlg) ? (appRouter.pushState({
dialogId: hash
}, "Dialog", "#" + hash), window.addEventListener("popstate", onHashChange)) : inputManager.on(dlg, onBackCommand)
}
function addBackdropOverlay(dlg) {
var backdrop = document.createElement("div");
backdrop.classList.add("dialogBackdrop");
var backdrop = document.createElement('div');
backdrop.classList.add('dialogBackdrop');
var backdropParent = dlg.dialogContainer || dlg;
backdropParent.parentNode.insertBefore(backdrop, backdropParent), dlg.backdrop = backdrop, backdrop.offsetWidth, backdrop.classList.add("dialogBackdropOpened"), dom.addEventListener(dlg.dialogContainer || backdrop, "click", function(e) {
e.target === dlg.dialogContainer && close(dlg)
backdropParent.parentNode.insertBefore(backdrop, backdropParent);
dlg.backdrop = backdrop;
// trigger reflow or the backdrop will not animate
void backdrop.offsetWidth;
backdrop.classList.add('dialogBackdropOpened');
dom.addEventListener((dlg.dialogContainer || backdrop), 'click', function (e) {
if (e.target === dlg.dialogContainer) {
close(dlg);
}
}, {
passive: !0
})
passive: true
});
}
function isHistoryEnabled(dlg) {
return "true" === dlg.getAttribute("data-history")
return dlg.getAttribute('data-history') === 'true';
}
function open(dlg) {
globalOnOpenCallback && globalOnOpenCallback(dlg);
if (globalOnOpenCallback) {
globalOnOpenCallback(dlg);
}
var parent = dlg.parentNode;
parent && parent.removeChild(dlg);
var dialogContainer = document.createElement("div");
return dialogContainer.classList.add("dialogContainer"), dialogContainer.appendChild(dlg), dlg.dialogContainer = dialogContainer, document.body.appendChild(dialogContainer), new Promise(function(resolve, reject) {
new DialogHashHandler(dlg, "dlg" + (new Date).getTime(), resolve)
})
if (parent) {
parent.removeChild(dlg);
}
var dialogContainer = document.createElement('div');
dialogContainer.classList.add('dialogContainer');
dialogContainer.appendChild(dlg);
dlg.dialogContainer = dialogContainer;
document.body.appendChild(dialogContainer);
return new Promise(function (resolve, reject) {
new DialogHashHandler(dlg, 'dlg' + new Date().getTime(), resolve);
});
}
function isOpened(dlg) {
return !dlg.classList.contains("hide")
//return dlg.opened;
return !dlg.classList.contains('hide');
}
function close(dlg) {
isOpened(dlg) && (isHistoryEnabled(dlg) ? history.back() : closeDialog(dlg))
if (isOpened(dlg)) {
if (isHistoryEnabled(dlg)) {
history.back();
} else {
closeDialog(dlg);
}
}
}
function closeDialog(dlg) {
if (!dlg.classList.contains("hide")) {
dlg.dispatchEvent(new CustomEvent("closing", {
bubbles: !1,
cancelable: !1
if (!dlg.classList.contains('hide')) {
dlg.dispatchEvent(new CustomEvent('closing', {
bubbles: false,
cancelable: false
}));
animateDialogClose(dlg, function() {
focusManager.popScope(dlg), dlg.classList.add("hide"), dlg.dispatchEvent(new CustomEvent("close", {
bubbles: !1,
cancelable: !1
}))
})
var onAnimationFinish = function () {
focusManager.popScope(dlg);
dlg.classList.add('hide');
dlg.dispatchEvent(new CustomEvent('close', {
bubbles: false,
cancelable: false
}));
};
animateDialogClose(dlg, onAnimationFinish);
}
}
function animateDialogOpen(dlg) {
var onAnimationFinish = function() {
focusManager.pushScope(dlg), "true" === dlg.getAttribute("data-autofocus") && focusManager.autoFocus(dlg)
var onAnimationFinish = function () {
focusManager.pushScope(dlg);
if (dlg.getAttribute('data-autofocus') === 'true') {
focusManager.autoFocus(dlg);
}
};
if (enableAnimation()) {
var onFinish = function() {
var onFinish = function () {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0
}), onAnimationFinish()
once: true
});
onAnimationFinish();
};
return void dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0
})
dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true
});
return;
}
onAnimationFinish()
onAnimationFinish();
}
function animateDialogClose(dlg, onAnimationFinish) {
if (enableAnimation()) {
var animated = !0;
var animated = true;
switch (dlg.animationConfig.exit.name) {
case "fadeout":
dlg.style.animation = "fadeout " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
case 'fadeout':
dlg.style.animation = 'fadeout ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
break;
case "scaledown":
dlg.style.animation = "scaledown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
case 'scaledown':
dlg.style.animation = 'scaledown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
break;
case "slidedown":
dlg.style.animation = "slidedown " + dlg.animationConfig.exit.timing.duration + "ms ease-out normal both";
case 'slidedown':
dlg.style.animation = 'slidedown ' + dlg.animationConfig.exit.timing.duration + 'ms ease-out normal both';
break;
default:
animated = !1
animated = false;
break;
}
var onFinish = function() {
var onFinish = function () {
dom.removeEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0
}), onAnimationFinish()
once: true
});
onAnimationFinish();
};
if (dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: !0
}), animated) return
dom.addEventListener(dlg, dom.whichAnimationEvent(), onFinish, {
once: true
});
if (animated) {
return;
}
}
onAnimationFinish()
onAnimationFinish();
}
var supportsOverscrollBehavior = 'overscroll-behavior-y' in document.body.style;
function shouldLockDocumentScroll(options) {
return !(supportsOverscrollBehavior && (options.size || !browser.touch)) && (null != options.lockScroll ? options.lockScroll : "fullscreen" === options.size || (!!options.size || browser.touch))
if (supportsOverscrollBehavior && (options.size || !browser.touch)) {
return false;
}
if (options.lockScroll != null) {
return options.lockScroll;
}
if (options.size === 'fullscreen') {
return true;
}
if (options.size) {
return true;
}
return browser.touch;
}
function removeBackdrop(dlg) {
var backdrop = dlg.backdrop;
if (backdrop) {
dlg.backdrop = null;
var onAnimationFinish = function() {
tryRemoveElement(backdrop)
};
if (enableAnimation()) return backdrop.classList.remove("dialogBackdropOpened"), void setTimeout(onAnimationFinish, 300);
onAnimationFinish()
if (!backdrop) {
return;
}
dlg.backdrop = null;
var onAnimationFinish = function () {
tryRemoveElement(backdrop);
};
if (enableAnimation()) {
backdrop.classList.remove('dialogBackdropOpened');
// this is not firing animatonend
setTimeout(onAnimationFinish, 300);
return;
}
onAnimationFinish();
}
function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) {
var fn = on ? "on" : "off";
scrollHelper.centerFocus[fn](elem, horiz)
})
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function createDialog(options) {
options = options || {};
var dlg = document.createElement("div");
dlg.classList.add("focuscontainer"), dlg.classList.add("hide"), shouldLockDocumentScroll(options) && dlg.setAttribute("data-lockscroll", "true"), !1 !== options.enableHistory && appRouter.enableNativeHistory() && dlg.setAttribute("data-history", "true"), !1 !== options.modal && dlg.setAttribute("modal", "modal"), !1 !== options.autoFocus && dlg.setAttribute("data-autofocus", "true");
var defaultEntryAnimation, defaultExitAnimation;
defaultEntryAnimation = "scaleup", defaultExitAnimation = "scaledown";
var entryAnimation = options.entryAnimation || defaultEntryAnimation,
exitAnimation = options.exitAnimation || defaultExitAnimation,
entryAnimationDuration = options.entryAnimationDuration || ("fullscreen" !== options.size ? 180 : 280),
exitAnimationDuration = options.exitAnimationDuration || ("fullscreen" !== options.size ? 120 : 220);
if (dlg.animationConfig = {
entry: {
name: entryAnimation,
timing: {
duration: entryAnimationDuration,
easing: "ease-out"
}
},
exit: {
name: exitAnimation,
timing: {
duration: exitAnimationDuration,
easing: "ease-out",
fill: "both"
}
}
}, dlg.classList.add("dialog"), options.scrollX ? (dlg.classList.add("scrollX"), dlg.classList.add("smoothScrollX"), layoutManager.tv && centerFocus(dlg, !0, !0)) : !1 !== options.scrollY && (dlg.classList.add("smoothScrollY"), layoutManager.tv && centerFocus(dlg, !1, !0)), options.removeOnClose && dlg.setAttribute("data-removeonclose", "true"), options.size && (dlg.classList.add("dialog-fixedSize"), dlg.classList.add("dialog-" + options.size)), enableAnimation()) switch (dlg.animationConfig.entry.name) {
case "fadein":
dlg.style.animation = "fadein " + entryAnimationDuration + "ms ease-out normal";
break;
case "scaleup":
dlg.style.animation = "scaleup " + entryAnimationDuration + "ms ease-out normal both";
break;
case "slideup":
dlg.style.animation = "slideup " + entryAnimationDuration + "ms ease-out normal";
break;
case "slidedown":
dlg.style.animation = "slidedown " + entryAnimationDuration + "ms ease-out normal"
// If there's no native dialog support, use a plain div
// Also not working well in samsung tizen browser, content inside not clickable
// Just go ahead and always use a plain div because we're seeing issues overlaying absoltutely positioned content over a modal dialog
var dlg = document.createElement('div');
dlg.classList.add('focuscontainer');
dlg.classList.add('hide');
if (shouldLockDocumentScroll(options)) {
dlg.setAttribute('data-lockscroll', 'true');
}
return dlg
if (options.enableHistory !== false && appRouter.enableNativeHistory()) {
dlg.setAttribute('data-history', 'true');
}
// without this safari will scroll the background instead of the dialog contents
// but not needed here since this is already on top of an existing dialog
// but skip it in IE because it's causing the entire browser to hang
// Also have to disable for firefox because it's causing select elements to not be clickable
if (options.modal !== false) {
dlg.setAttribute('modal', 'modal');
}
if (options.autoFocus !== false) {
dlg.setAttribute('data-autofocus', 'true');
}
var defaultEntryAnimation;
var defaultExitAnimation;
defaultEntryAnimation = 'scaleup';
defaultExitAnimation = 'scaledown';
var entryAnimation = options.entryAnimation || defaultEntryAnimation;
var exitAnimation = options.exitAnimation || defaultExitAnimation;
// If it's not fullscreen then lower the default animation speed to make it open really fast
var entryAnimationDuration = options.entryAnimationDuration || (options.size !== 'fullscreen' ? 180 : 280);
var exitAnimationDuration = options.exitAnimationDuration || (options.size !== 'fullscreen' ? 120 : 220);
dlg.animationConfig = {
// scale up
'entry': {
name: entryAnimation,
timing: {
duration: entryAnimationDuration,
easing: 'ease-out'
}
},
// fade out
'exit': {
name: exitAnimation,
timing: {
duration: exitAnimationDuration,
easing: 'ease-out',
fill: 'both'
}
}
};
dlg.classList.add('dialog');
if (options.scrollX) {
dlg.classList.add('scrollX');
dlg.classList.add('smoothScrollX');
if (layoutManager.tv) {
centerFocus(dlg, true, true);
}
}
else if (options.scrollY !== false) {
dlg.classList.add('smoothScrollY');
if (layoutManager.tv) {
centerFocus(dlg, false, true);
}
}
if (options.removeOnClose) {
dlg.setAttribute('data-removeonclose', 'true');
}
if (options.size) {
dlg.classList.add('dialog-fixedSize');
dlg.classList.add('dialog-' + options.size);
}
if (enableAnimation()) {
switch (dlg.animationConfig.entry.name) {
case 'fadein':
dlg.style.animation = 'fadein ' + entryAnimationDuration + 'ms ease-out normal';
break;
case 'scaleup':
dlg.style.animation = 'scaleup ' + entryAnimationDuration + 'ms ease-out normal both';
break;
case 'slideup':
dlg.style.animation = 'slideup ' + entryAnimationDuration + 'ms ease-out normal';
break;
case 'slidedown':
dlg.style.animation = 'slidedown ' + entryAnimationDuration + 'ms ease-out normal';
break;
default:
break;
}
}
return dlg;
}
var globalOnOpenCallback, supportsOverscrollBehavior = "overscroll-behavior-y" in document.body.style;
return {
open: open,
close: close,
createDialog: createDialog,
setOnOpen: function(val) {
globalOnOpenCallback = val
setOnOpen: function (val) {
globalOnOpenCallback = val;
}
}
};
});
@@ -1,122 +1,343 @@
define(["require", "browser", "layoutManager", "appSettings", "pluginManager", "apphost", "focusManager", "datetime", "globalize", "loading", "connectionManager", "skinManager", "dom", "events", "emby-select", "emby-checkbox", "emby-linkbutton"], function(require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-linkbutton'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) {
"use strict";
function fillThemes(select, isDashboard) {
select.innerHTML = skinManager.getThemes().map(function(t) {
select.innerHTML = skinManager.getThemes().map(function (t) {
var value = t.id;
return t.isDefault && !isDashboard ? value = "" : t.isDefaultServerDashboard && isDashboard && (value = ""), '<option value="' + value + '">' + t.name + "</option>"
}).join("")
if (t.isDefault && !isDashboard) {
value = '';
}
else if (t.isDefaultServerDashboard && isDashboard) {
value = '';
}
return '<option value="' + value + '">' + t.name + '</option>';
}).join('');
}
function loadScreensavers(context, userSettings) {
var selectScreensaver = context.querySelector(".selectScreensaver"),
options = pluginManager.ofType("screensaver").map(function(plugin) {
return {
name: plugin.name,
value: plugin.id
}
});
var selectScreensaver = context.querySelector('.selectScreensaver');
var options = pluginManager.ofType('screensaver').map(function (plugin) {
return {
name: plugin.name,
value: plugin.id
};
});
options.unshift({
name: globalize.translate("sharedcomponents#None"),
value: "none"
}), selectScreensaver.innerHTML = options.map(function(o) {
return '<option value="' + o.value + '">' + o.name + "</option>"
}).join(""), selectScreensaver.value = userSettings.screensaver(), selectScreensaver.value || (selectScreensaver.value = "none")
name: globalize.translate('sharedcomponents#None'),
value: 'none'
});
selectScreensaver.innerHTML = options.map(function (o) {
return '<option value="' + o.value + '">' + o.name + '</option>';
}).join('');
selectScreensaver.value = userSettings.screensaver();
if (!selectScreensaver.value) {
// TODO: set the default instead of none
selectScreensaver.value = 'none';
}
}
function loadSoundEffects(context, userSettings) {
var selectSoundEffects = context.querySelector(".selectSoundEffects"),
options = pluginManager.ofType("soundeffects").map(function(plugin) {
return {
name: plugin.name,
value: plugin.id
}
});
var selectSoundEffects = context.querySelector('.selectSoundEffects');
var options = pluginManager.ofType('soundeffects').map(function (plugin) {
return {
name: plugin.name,
value: plugin.id
};
});
options.unshift({
name: globalize.translate("sharedcomponents#None"),
value: "none"
}), selectSoundEffects.innerHTML = options.map(function(o) {
return '<option value="' + o.value + '">' + o.name + "</option>"
}).join(""), selectSoundEffects.value = userSettings.soundEffects(), selectSoundEffects.value || (selectSoundEffects.value = "none")
name: globalize.translate('sharedcomponents#None'),
value: 'none'
});
selectSoundEffects.innerHTML = options.map(function (o) {
return '<option value="' + o.value + '">' + o.name + '</option>';
}).join('');
selectSoundEffects.value = userSettings.soundEffects();
if (!selectSoundEffects.value) {
// TODO: set the default instead of none
selectSoundEffects.value = 'none';
}
}
function loadSkins(context, userSettings) {
var selectSkin = context.querySelector(".selectSkin"),
options = pluginManager.ofType("skin").map(function(plugin) {
return {
name: plugin.name,
value: plugin.id
}
});
selectSkin.innerHTML = options.map(function(o) {
return '<option value="' + o.value + '">' + o.name + "</option>"
}).join(""), selectSkin.value = userSettings.skin(), !selectSkin.value && options.length && (selectSkin.value = options[0].value), options.length > 1 && appHost.supports("skins") ? context.querySelector(".selectSkinContainer").classList.remove("hide") : context.querySelector(".selectSkinContainer").classList.add("hide")
var selectSkin = context.querySelector('.selectSkin');
var options = pluginManager.ofType('skin').map(function (plugin) {
return {
name: plugin.name,
value: plugin.id
};
});
selectSkin.innerHTML = options.map(function (o) {
return '<option value="' + o.value + '">' + o.name + '</option>';
}).join('');
selectSkin.value = userSettings.skin();
if (!selectSkin.value && options.length) {
selectSkin.value = options[0].value;
}
if (options.length > 1 && appHost.supports('skins')) {
context.querySelector('.selectSkinContainer').classList.remove('hide');
} else {
context.querySelector('.selectSkinContainer').classList.add('hide');
}
}
function showOrHideMissingEpisodesField(context, user, apiClient) {
if (browser.tizen || browser.web0s) return void context.querySelector(".fldDisplayMissingEpisodes").classList.add("hide");
context.querySelector(".fldDisplayMissingEpisodes").classList.remove("hide")
if (browser.tizen || browser.web0s) {
context.querySelector('.fldDisplayMissingEpisodes').classList.add('hide');
return;
}
context.querySelector('.fldDisplayMissingEpisodes').classList.remove('hide');
}
function loadForm(context, user, userSettings, apiClient) {
apiClient.getCurrentUserId(), user.Id;
user.Policy.IsAdministrator ? context.querySelector(".selectDashboardThemeContainer").classList.remove("hide") : context.querySelector(".selectDashboardThemeContainer").classList.add("hide"), appHost.supports("displaylanguage") ? context.querySelector(".languageSection").classList.remove("hide") : context.querySelector(".languageSection").classList.add("hide"), appHost.supports("displaymode") ? context.querySelector(".fldDisplayMode").classList.remove("hide") : context.querySelector(".fldDisplayMode").classList.add("hide"), appHost.supports("externallinks") ? context.querySelector(".learnHowToContributeContainer").classList.remove("hide") : context.querySelector(".learnHowToContributeContainer").classList.add("hide"), appHost.supports("runatstartup") ? context.querySelector(".fldAutorun").classList.remove("hide") : context.querySelector(".fldAutorun").classList.add("hide"), appHost.supports("soundeffects") ? context.querySelector(".fldSoundEffects").classList.remove("hide") : context.querySelector(".fldSoundEffects").classList.add("hide"), appHost.supports("screensaver") ? context.querySelector(".selectScreensaverContainer").classList.remove("hide") : context.querySelector(".selectScreensaverContainer").classList.add("hide"), datetime.supportsLocalization() ? context.querySelector(".fldDateTimeLocale").classList.remove("hide") : context.querySelector(".fldDateTimeLocale").classList.add("hide"), browser.tizen || browser.web0s ? (context.querySelector(".fldSeasonalThemes").classList.add("hide"), context.querySelector(".fldBackdrops").classList.add("hide"), context.querySelector(".fldThemeSong").classList.add("hide"), context.querySelector(".fldThemeVideo").classList.add("hide")) : (context.querySelector(".fldSeasonalThemes").classList.remove("hide"), context.querySelector(".fldBackdrops").classList.remove("hide"), context.querySelector(".fldThemeSong").classList.remove("hide"), context.querySelector(".fldThemeVideo").classList.remove("hide")), context.querySelector(".chkRunAtStartup").checked = appSettings.runAtStartup();
var selectTheme = context.querySelector("#selectTheme"),
selectDashboardTheme = context.querySelector("#selectDashboardTheme");
fillThemes(selectTheme), fillThemes(selectDashboardTheme, !0), loadScreensavers(context, userSettings), loadSoundEffects(context, userSettings), loadSkins(context, userSettings), context.querySelector(".chkDisplayMissingEpisodes").checked = user.Configuration.DisplayMissingEpisodes || !1, context.querySelector("#chkThemeSong").checked = userSettings.enableThemeSongs(), context.querySelector("#chkThemeVideo").checked = userSettings.enableThemeVideos(), context.querySelector("#chkBackdrops").checked = userSettings.enableBackdrops(), context.querySelector("#chkSeasonalThemes").checked = userSettings.enableSeasonalThemes(), context.querySelector("#selectLanguage").value = userSettings.language() || "", context.querySelector(".selectDateTimeLocale").value = userSettings.dateTimeLocale() || "", selectDashboardTheme.value = userSettings.dashboardTheme() || "", selectTheme.value = userSettings.theme() || "", context.querySelector(".selectLayout").value = layoutManager.getSavedLayout() || "", showOrHideMissingEpisodesField(context, user, apiClient), loading.hide()
var loggedInUserId = apiClient.getCurrentUserId();
var userId = user.Id;
if (user.Policy.IsAdministrator) {
context.querySelector('.selectDashboardThemeContainer').classList.remove('hide');
} else {
context.querySelector('.selectDashboardThemeContainer').classList.add('hide');
}
if (appHost.supports('displaylanguage')) {
context.querySelector('.languageSection').classList.remove('hide');
} else {
context.querySelector('.languageSection').classList.add('hide');
}
if (appHost.supports('displaymode')) {
context.querySelector('.fldDisplayMode').classList.remove('hide');
} else {
context.querySelector('.fldDisplayMode').classList.add('hide');
}
if (appHost.supports('externallinks')) {
context.querySelector('.learnHowToContributeContainer').classList.remove('hide');
} else {
context.querySelector('.learnHowToContributeContainer').classList.add('hide');
}
if (appHost.supports('runatstartup')) {
context.querySelector('.fldAutorun').classList.remove('hide');
} else {
context.querySelector('.fldAutorun').classList.add('hide');
}
if (appHost.supports('soundeffects')) {
context.querySelector('.fldSoundEffects').classList.remove('hide');
} else {
context.querySelector('.fldSoundEffects').classList.add('hide');
}
if (appHost.supports('screensaver')) {
context.querySelector('.selectScreensaverContainer').classList.remove('hide');
} else {
context.querySelector('.selectScreensaverContainer').classList.add('hide');
}
if (datetime.supportsLocalization()) {
context.querySelector('.fldDateTimeLocale').classList.remove('hide');
} else {
context.querySelector('.fldDateTimeLocale').classList.add('hide');
}
if (!browser.tizen && !browser.web0s) {
context.querySelector('.fldSeasonalThemes').classList.remove('hide');
context.querySelector('.fldBackdrops').classList.remove('hide');
context.querySelector('.fldThemeSong').classList.remove('hide');
context.querySelector('.fldThemeVideo').classList.remove('hide');
} else {
context.querySelector('.fldSeasonalThemes').classList.add('hide');
context.querySelector('.fldBackdrops').classList.add('hide');
context.querySelector('.fldThemeSong').classList.add('hide');
context.querySelector('.fldThemeVideo').classList.add('hide');
}
context.querySelector('.chkRunAtStartup').checked = appSettings.runAtStartup();
var selectTheme = context.querySelector('#selectTheme');
var selectDashboardTheme = context.querySelector('#selectDashboardTheme');
fillThemes(selectTheme);
fillThemes(selectDashboardTheme, true);
loadScreensavers(context, userSettings);
loadSoundEffects(context, userSettings);
loadSkins(context, userSettings);
context.querySelector('.chkDisplayMissingEpisodes').checked = user.Configuration.DisplayMissingEpisodes || false;
context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs();
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
context.querySelector('#chkSeasonalThemes').checked = userSettings.enableSeasonalThemes();
context.querySelector('#selectLanguage').value = userSettings.language() || '';
context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || '';
selectDashboardTheme.value = userSettings.dashboardTheme() || '';
selectTheme.value = userSettings.theme() || '';
context.querySelector('.selectLayout').value = layoutManager.getSavedLayout() || '';
showOrHideMissingEpisodesField(context, user, apiClient);
loading.hide();
}
function saveUser(context, user, userSettingsInstance, apiClient) {
return appSettings.runAtStartup(context.querySelector(".chkRunAtStartup").checked), user.Configuration.DisplayMissingEpisodes = context.querySelector(".chkDisplayMissingEpisodes").checked, appHost.supports("displaylanguage") && userSettingsInstance.language(context.querySelector("#selectLanguage").value), userSettingsInstance.dateTimeLocale(context.querySelector(".selectDateTimeLocale").value), userSettingsInstance.enableThemeSongs(context.querySelector("#chkThemeSong").checked), userSettingsInstance.enableThemeVideos(context.querySelector("#chkThemeVideo").checked), userSettingsInstance.dashboardTheme(context.querySelector("#selectDashboardTheme").value), userSettingsInstance.theme(context.querySelector("#selectTheme").value), userSettingsInstance.soundEffects(context.querySelector(".selectSoundEffects").value), userSettingsInstance.screensaver(context.querySelector(".selectScreensaver").value), userSettingsInstance.skin(context.querySelector(".selectSkin").value), userSettingsInstance.enableBackdrops(context.querySelector("#chkBackdrops").checked), userSettingsInstance.enableSeasonalThemes(context.querySelector("#chkSeasonalThemes").checked), user.Id === apiClient.getCurrentUserId() && skinManager.setTheme(userSettingsInstance.theme()), layoutManager.setLayout(context.querySelector(".selectLayout").value), apiClient.updateUserConfiguration(user.Id, user.Configuration)
appSettings.runAtStartup(context.querySelector('.chkRunAtStartup').checked);
user.Configuration.DisplayMissingEpisodes = context.querySelector('.chkDisplayMissingEpisodes').checked;
if (appHost.supports('displaylanguage')) {
userSettingsInstance.language(context.querySelector('#selectLanguage').value);
}
userSettingsInstance.dateTimeLocale(context.querySelector('.selectDateTimeLocale').value);
userSettingsInstance.enableThemeSongs(context.querySelector('#chkThemeSong').checked);
userSettingsInstance.enableThemeVideos(context.querySelector('#chkThemeVideo').checked);
userSettingsInstance.dashboardTheme(context.querySelector('#selectDashboardTheme').value);
userSettingsInstance.theme(context.querySelector('#selectTheme').value);
userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value);
userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value);
userSettingsInstance.skin(context.querySelector('.selectSkin').value);
userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked);
userSettingsInstance.enableSeasonalThemes(context.querySelector('#chkSeasonalThemes').checked);
if (user.Id === apiClient.getCurrentUserId()) {
skinManager.setTheme(userSettingsInstance.theme());
}
layoutManager.setLayout(context.querySelector('.selectLayout').value);
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
}
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show(), apiClient.getUser(userId).then(function(user) {
saveUser(context, user, userSettings, apiClient).then(function() {
loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) {
toast(globalize.translate("sharedcomponents#SettingsSaved"))
}), events.trigger(instance, "saved")
}, function() {
loading.hide()
})
})
loading.show();
apiClient.getUser(userId).then(function (user) {
saveUser(context, user, userSettings, apiClient).then(function () {
loading.hide();
if (enableSaveConfirmation) {
require(['toast'], function (toast) {
toast(globalize.translate('sharedcomponents#SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, function () {
loading.hide();
});
});
}
function onSubmit(e) {
var self = this,
apiClient = connectionManager.getApiClient(self.options.serverId),
userId = self.options.userId,
userSettings = self.options.userSettings;
return userSettings.setUserInfo(userId, apiClient).then(function() {
var self = this;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userId = self.options.userId;
var userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function () {
var enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation)
}), e && e.preventDefault(), !1
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
});
// Disable default form submission
if (e) {
e.preventDefault();
}
return false;
}
function embed(options, self) {
require(["text!./displaysettings.template.html"], function(template) {
options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), self.loadData(options.autoFocus)
})
require(['text!./displaysettings.template.html'], function (template) {
options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
if (options.enableSaveButton) {
options.element.querySelector('.btnSave').classList.remove('hide');
}
self.loadData(options.autoFocus);
});
}
function DisplaySettings(options) {
this.options = options, embed(options, this)
this.options = options;
embed(options, this);
}
return DisplaySettings.prototype.loadData = function(autoFocus) {
var self = this,
context = self.options.element;
DisplaySettings.prototype.loadData = function (autoFocus) {
var self = this;
var context = self.options.element;
loading.show();
var userId = self.options.userId,
apiClient = connectionManager.getApiClient(self.options.serverId),
userSettings = self.options.userSettings;
return apiClient.getUser(userId).then(function(user) {
return userSettings.setUserInfo(userId, apiClient).then(function() {
self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context)
})
})
}, DisplaySettings.prototype.submit = function() {
onSubmit.call(this)
}, DisplaySettings.prototype.destroy = function() {
this.options = null
}, DisplaySettings
var userId = self.options.userId;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userSettings = self.options.userSettings;
return apiClient.getUser(userId).then(function (user) {
return userSettings.setUserInfo(userId, apiClient).then(function () {
self.dataLoaded = true;
loadForm(context, user, userSettings, apiClient);
if (autoFocus) {
focusManager.autoFocus(context);
}
});
});
};
DisplaySettings.prototype.submit = function () {
onSubmit.call(this);
};
DisplaySettings.prototype.destroy = function () {
this.options = null;
};
return DisplaySettings;
});
+133 -59
View File
@@ -1,96 +1,170 @@
define([], function() {
"use strict";
define([], function () {
'use strict';
function parentWithAttribute(elem, name, value) {
for (; value ? elem.getAttribute(name) !== value : !elem.getAttribute(name);)
if (!(elem = elem.parentNode) || !elem.getAttribute) return null;
return elem
while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) {
elem = elem.parentNode;
if (!elem || !elem.getAttribute) {
return null;
}
}
return elem;
}
function parentWithTag(elem, tagNames) {
for (Array.isArray(tagNames) || (tagNames = [tagNames]); - 1 === tagNames.indexOf(elem.tagName || "");)
if (!(elem = elem.parentNode)) return null;
return elem
// accept both string and array passed in
if (!Array.isArray(tagNames)) {
tagNames = [tagNames];
}
while (tagNames.indexOf(elem.tagName || '') === -1) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
}
function containsAnyClass(classList, classNames) {
for (var i = 0, length = classNames.length; i < length; i++)
if (classList.contains(classNames[i])) return !0;
return !1
for (var i = 0, length = classNames.length; i < length; i++) {
if (classList.contains(classNames[i])) {
return true;
}
}
return false;
}
function parentWithClass(elem, classNames) {
for (Array.isArray(classNames) || (classNames = [classNames]); !elem.classList || !containsAnyClass(elem.classList, classNames);)
if (!(elem = elem.parentNode)) return null;
return elem
// accept both string and array passed in
if (!Array.isArray(classNames)) {
classNames = [classNames];
}
while (!elem.classList || !containsAnyClass(elem.classList, classNames)) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
}
var supportsCaptureOption = false;
try {
var opts = Object.defineProperty({}, 'capture', {
get: function () {
supportsCaptureOption = true;
}
});
window.addEventListener("test", null, opts);
} catch (e) { }
function addEventListenerWithOptions(target, type, handler, options) {
var optionsOrCapture = options;
supportsCaptureOption || (optionsOrCapture = options.capture), target.addEventListener(type, handler, optionsOrCapture)
if (!supportsCaptureOption) {
optionsOrCapture = options.capture;
}
target.addEventListener(type, handler, optionsOrCapture);
}
function removeEventListenerWithOptions(target, type, handler, options) {
var optionsOrCapture = options;
supportsCaptureOption || (optionsOrCapture = options.capture), target.removeEventListener(type, handler, optionsOrCapture)
if (!supportsCaptureOption) {
optionsOrCapture = options.capture;
}
target.removeEventListener(type, handler, optionsOrCapture);
}
var windowSize;
var windowSizeEventsBound;
function clearWindowSize() {
windowSize = null
windowSize = null;
}
function getWindowSize() {
return windowSize || (windowSize = {
innerHeight: window.innerHeight,
innerWidth: window.innerWidth
}, windowSizeEventsBound || (windowSizeEventsBound = !0, addEventListenerWithOptions(window, "orientationchange", clearWindowSize, {
passive: !0
}), addEventListenerWithOptions(window, "resize", clearWindowSize, {
passive: !0
}))), windowSize
if (!windowSize) {
windowSize = {
innerHeight: window.innerHeight,
innerWidth: window.innerWidth
};
if (!windowSizeEventsBound) {
windowSizeEventsBound = true;
addEventListenerWithOptions(window, "orientationchange", clearWindowSize, { passive: true });
addEventListenerWithOptions(window, 'resize', clearWindowSize, { passive: true });
}
}
return windowSize;
}
var _animationEvent;
function whichAnimationEvent() {
if (_animationEvent) return _animationEvent;
var t, el = document.createElement("div"),
animations = {
animation: "animationend",
OAnimation: "oAnimationEnd",
MozAnimation: "animationend",
WebkitAnimation: "webkitAnimationEnd"
};
for (t in animations)
if (void 0 !== el.style[t]) return _animationEvent = animations[t], animations[t];
return _animationEvent = "animationend"
if (_animationEvent) {
return _animationEvent;
}
var t,
el = document.createElement("div");
var animations = {
"animation": "animationend",
"OAnimation": "oAnimationEnd",
"MozAnimation": "animationend",
"WebkitAnimation": "webkitAnimationEnd"
};
for (t in animations) {
if (el.style[t] !== undefined) {
_animationEvent = animations[t];
return animations[t];
}
}
_animationEvent = 'animationend';
return _animationEvent;
}
function whichAnimationCancelEvent() {
return whichAnimationEvent().replace("animationend", "animationcancel").replace("AnimationEnd", "AnimationCancel")
return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel');
}
var _transitionEvent;
function whichTransitionEvent() {
if (_transitionEvent) return _transitionEvent;
var t, el = document.createElement("div"),
transitions = {
transition: "transitionend",
OTransition: "oTransitionEnd",
MozTransition: "transitionend",
WebkitTransition: "webkitTransitionEnd"
};
for (t in transitions)
if (void 0 !== el.style[t]) return _transitionEvent = transitions[t], transitions[t];
return _transitionEvent = "transitionend"
}
var supportsCaptureOption = !1;
try {
var opts = Object.defineProperty({}, "capture", {
get: function() {
supportsCaptureOption = !0
if (_transitionEvent) {
return _transitionEvent;
}
var t,
el = document.createElement("div");
var transitions = {
"transition": "transitionend",
"OTransition": "oTransitionEnd",
"MozTransition": "transitionend",
"WebkitTransition": "webkitTransitionEnd"
};
for (t in transitions) {
if (el.style[t] !== undefined) {
_transitionEvent = transitions[t];
return transitions[t];
}
});
window.addEventListener("test", null, opts)
} catch (e) {}
var windowSize, windowSizeEventsBound, _animationEvent, _transitionEvent;
}
_transitionEvent = 'transitionend';
return _transitionEvent;
}
return {
parentWithAttribute: parentWithAttribute,
parentWithClass: parentWithClass,
@@ -101,5 +175,5 @@ define([], function() {
whichTransitionEvent: whichTransitionEvent,
whichAnimationEvent: whichAnimationEvent,
whichAnimationCancelEvent: whichAnimationCancelEvent
}
};
});
@@ -1,33 +1,14 @@
.emby-button,
.fab {
-webkit-box-sizing: border-box;
-webkit-box-align: center
}
.button-flat,
.button-link {
background: 0 0
}
.emby-button,
.paper-icon-button-light {
text-align: center;
font-family: inherit;
color: inherit;
outline: 0 !important;
-webkit-tap-highlight-color: transparent;
position: relative
}
.emby-button {
display: -webkit-inline-box;
display: -webkit-inline-flex;
position: relative;
display: inline-flex;
-webkit-align-items: center;
align-items: center;
box-sizing: border-box;
margin: 0 .29em;
text-align: center;
font-size: inherit;
font-family: inherit;
color: inherit;
outline-width: 0;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
@@ -35,99 +16,98 @@
cursor: pointer;
z-index: 0;
padding: .86em 1em;
vertical-align: middle;
border: 0;
vertical-align: middle;
-webkit-border-radius: .2em;
border-radius: .2em;
/* These are getting an outline in opera tv browsers, which run chrome 30 */
outline: none !important;
position: relative;
font-weight: 600;
/* Disable webkit tap highlighting */
-webkit-tap-highlight-color: rgba(0,0,0,0);
text-decoration: none;
line-height: 1.35
/* Not crazy about this but it normalizes heights between anchors and buttons */
line-height: 1.35;
}
.emby-button::-moz-focus-inner {
border: 0
border: 0;
}
.button-flat:hover {
opacity: .5
.button-flat {
background: transparent;
}
.button-flat:hover {
opacity: .5;
}
.button-link {
background: transparent;
margin: 0;
padding: 0;
vertical-align: initial
vertical-align: initial;
}
.button-link-inline {
display: inline
display: inline;
}
.button-link:hover {
text-decoration: underline
text-decoration: underline;
}
.emby-button-focusscale {
-webkit-transition: -webkit-transform 180ms ease-out !important;
-o-transition: transform 180ms ease-out !important;
transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center;
transform-origin: center center
transform-origin: center center;
}
.emby-button-focusscale:focus {
-webkit-transform: scale(1.16);
transform: scale(1.16);
z-index: 1
.emby-button-focusscale:focus {
transform: scale(1.16);
z-index: 1;
}
.emby-button > i {
/* For non-fab buttons that have icons */
font-size: 1.36em;
}
.emby-button>i {
font-size: 1.36em
}
.button-link>i {
font-size: 1em
.button-link > i {
font-size: 1em;
}
.fab {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
-webkit-border-radius: 50%;
border-radius: 50%;
padding: .6em;
box-sizing: border-box;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
text-align: center
text-align: center;
}
.emby-button.block {
display: block;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
margin: .25em 0;
width: 100%
width: 100%;
}
.paper-icon-button-light {
display: -webkit-inline-box;
display: -webkit-inline-flex;
position: relative;
display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0 .29em;
background: 0 0;
background: transparent;
text-align: center;
font-size: inherit;
font-family: inherit;
color: inherit;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
@@ -139,84 +119,82 @@
width: auto;
height: auto;
padding: .556em;
vertical-align: middle;
border: 0;
vertical-align: middle;
/* These are getting an outline in opera tv browsers, which run chrome 30 */
outline: none !important;
position: relative;
overflow: hidden;
-webkit-border-radius: 50%;
border-radius: 50%;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center
/* Disable webkit tap highlighting */
-webkit-tap-highlight-color: rgba(0,0,0,0);
justify-content: center;
}
.paper-icon-button-light::-moz-focus-inner {
border: 0
}
.paper-icon-button-light::-moz-focus-inner {
border: 0;
}
.paper-icon-button-light[disabled] {
opacity: .3
}
.paper-icon-button-light[disabled] {
opacity: .3;
}
.paper-icon-button-light>i {
font-size: 1.66956521739130434em;
position: relative;
z-index: 1;
vertical-align: middle
}
.paper-icon-button-light > i {
font-size: 1.66956521739130434em;
/* Make sure its on top of the ripple */
position: relative;
z-index: 1;
vertical-align: middle;
}
.paper-icon-button-light>img {
width: 1.72em;
max-height: 100%;
position: relative;
z-index: 1;
vertical-align: middle
}
.paper-icon-button-light > img {
width: 1.72em;
/* Can't use 100% height or it will stretch past the boundaries in safari */
/*height: 100%;*/
max-height: 100%;
/* Make sure its on top of the ripple */
position: relative;
z-index: 1;
vertical-align: middle;
}
.emby-button-foreground {
position: relative;
z-index: 1
z-index: 1;
}
.icon-button-focusscale {
-webkit-transition: -webkit-transform 180ms ease-out !important;
-o-transition: transform 180ms ease-out !important;
transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center;
transform-origin: center center
transform-origin: center center;
}
.icon-button-focusscale:focus {
-webkit-transform: scale(1.3);
transform: scale(1.3);
z-index: 1
}
.icon-button-focusscale:focus {
transform: scale(1.3);
z-index: 1;
}
.btnFilterWithBubble {
position: relative
position: relative;
}
.filterButtonBubble {
color: #fff;
position: absolute;
background: #444;
top: 0;
right: 0;
/* padding: .5em; */
width: 1.6em;
height: 1.6em;
z-index: 100000000;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
font-size: 82%;
-webkit-border-radius: 100em;
border-radius: 100em;
-webkit-box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2);
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2);
box-shadow: 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12), 0px 2px 4px -1px rgba(0, 0, 0, 0.2);
background: #03A9F4;
font-weight: 700
}
font-weight: bold;
}
@@ -1,29 +1,99 @@
define(["browser", "dom", "layoutManager", "shell", "appRouter", "apphost", "css!./emby-button", "registerElement"], function(browser, dom, layoutManager, shell, appRouter, appHost) {
"use strict";
define(['browser', 'dom', 'layoutManager', 'shell', 'appRouter', 'apphost', 'css!./emby-button', 'registerElement'], function (browser, dom, layoutManager, shell, appRouter, appHost) {
'use strict';
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
var EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype);
function openPremiumInfo() {
require(["registrationServices"], function(registrationServices) {
registrationServices.showPremiereInfo()
})
require(['registrationServices'], function (registrationServices) {
registrationServices.showPremiereInfo();
});
}
function onAnchorClick(e) {
var href = this.getAttribute("href") || "";
"#" !== href ? this.getAttribute("target") ? -1 === href.indexOf("emby.media/premiere") || appHost.supports("externalpremium") ? appHost.supports("targetblank") || (e.preventDefault(), shell.openUrl(href)) : (e.preventDefault(), openPremiumInfo()) : appRouter.handleAnchorClick(e) : e.preventDefault()
var href = this.getAttribute('href') || '';
if (href !== '#') {
if (this.getAttribute('target')) {
if (href.indexOf('emby.media/premiere') !== -1 && !appHost.supports('externalpremium')) {
e.preventDefault();
openPremiumInfo();
}
else if (!appHost.supports('targetblank')) {
e.preventDefault();
shell.openUrl(href);
}
} else {
appRouter.handleAnchorClick(e);
}
} else {
e.preventDefault();
}
}
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype),
EmbyLinkButtonPrototype = Object.create(HTMLAnchorElement.prototype);
return EmbyButtonPrototype.createdCallback = function() {
this.classList.contains("emby-button") || (this.classList.add("emby-button"), browser.firefox && this.classList.add("button-link-inline"), layoutManager.tv && ("false" !== this.getAttribute("data-focusscale") && this.classList.add("emby-button-focusscale"), this.classList.add("emby-button-tv")))
}, EmbyButtonPrototype.attachedCallback = function() {
"A" === this.tagName && (dom.removeEventListener(this, "click", onAnchorClick, {}), dom.addEventListener(this, "click", onAnchorClick, {}), "true" === this.getAttribute("data-autohide") && (appHost.supports("externallinks") ? this.classList.remove("hide") : this.classList.add("hide")))
}, EmbyButtonPrototype.detachedCallback = function() {
dom.removeEventListener(this, "click", onAnchorClick, {})
}, EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback, EmbyLinkButtonPrototype.attachedCallback = EmbyButtonPrototype.attachedCallback, document.registerElement("emby-button", {
EmbyButtonPrototype.createdCallback = function () {
if (this.classList.contains('emby-button')) {
return;
}
this.classList.add('emby-button');
if (browser.firefox) {
// a ff hack is needed for vertical alignment
this.classList.add('button-link-inline');
}
if (layoutManager.tv) {
if (this.getAttribute('data-focusscale') !== 'false') {
this.classList.add('emby-button-focusscale');
}
this.classList.add('emby-button-tv');
}
};
EmbyButtonPrototype.attachedCallback = function () {
if (this.tagName === 'A') {
dom.removeEventListener(this, 'click', onAnchorClick, {
});
dom.addEventListener(this, 'click', onAnchorClick, {
});
if (this.getAttribute('data-autohide') === 'true') {
if (appHost.supports('externallinks')) {
this.classList.remove('hide');
} else {
this.classList.add('hide');
}
}
}
};
EmbyButtonPrototype.detachedCallback = function () {
dom.removeEventListener(this, 'click', onAnchorClick, {
});
};
EmbyLinkButtonPrototype.createdCallback = EmbyButtonPrototype.createdCallback;
EmbyLinkButtonPrototype.attachedCallback = EmbyButtonPrototype.attachedCallback;
document.registerElement('emby-button', {
prototype: EmbyButtonPrototype,
extends: "button"
}), document.registerElement("emby-linkbutton", {
extends: 'button'
});
document.registerElement('emby-linkbutton', {
prototype: EmbyLinkButtonPrototype,
extends: "a"
}), EmbyButtonPrototype
extends: 'a'
});
// For extension purposes
return EmbyButtonPrototype;
});
@@ -1,10 +1,19 @@
define(["layoutManager", "css!./emby-button", "registerElement"], function(layoutManager) {
"use strict";
define(['layoutManager', 'css!./emby-button', 'registerElement'], function (layoutManager) {
'use strict';
var EmbyButtonPrototype = Object.create(HTMLButtonElement.prototype);
EmbyButtonPrototype.createdCallback = function() {
this.classList.add("paper-icon-button-light"), layoutManager.tv && this.classList.add("icon-button-focusscale")
}, document.registerElement("paper-icon-button-light", {
EmbyButtonPrototype.createdCallback = function () {
this.classList.add('paper-icon-button-light');
if (layoutManager.tv) {
this.classList.add('icon-button-focusscale');
}
};
document.registerElement('paper-icon-button-light', {
prototype: EmbyButtonPrototype,
extends: "button"
})
extends: 'button'
});
});
@@ -2,45 +2,37 @@
position: relative;
z-index: 1;
vertical-align: middle;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
margin: 0;
padding: 0 0 0 2.4em;
-webkit-box-align: center;
-webkit-align-items: center;
padding: 0;
padding-left: 2.4em;
align-items: center;
height: 2.35em;
cursor: pointer
}
.checkboxContainer,
.checkboxListContainer {
margin-bottom: 1.8em
cursor: pointer;
}
.checkboxFieldDescription {
padding-left: 2.4em
padding-left: 2.4em;
}
.checkboxContainer {
display: -webkit-box;
display: -webkit-flex;
display: flex
margin-bottom: 1.8em;
display: flex;
}
.checkboxListContainer {
margin-bottom: 1.8em;
}
.checkboxContainer-withDescription {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column
flex-direction: column;
}
.emby-checkbox {
position: absolute;
/* This is for focusing purposes, so the focusManager doesn't skip over it */
width: 1px;
height: 1px;
margin: 0;
@@ -50,112 +42,109 @@
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
border: none
border: none;
}
.checkboxOutline {
position: absolute;
top: 3px;
left: 0;
-webkit-box-sizing: border-box;
display: inline-block;
box-sizing: border-box;
width: 1.83em;
height: 1.83em;
margin: 0;
overflow: hidden;
border: 2px solid currentcolor;
-webkit-border-radius: .14em;
border-radius: .14em;
z-index: 2;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center
justify-content: center;
}
/* Commenting this out - set by theme */
/*.emby-checkbox:checked + span + span + .checkboxOutline {
border-color: #52B54B;
}*/
.emby-checkbox-focushelper {
position: absolute;
top: -.915em;
left: -.915em;
top: -0.915em;
left: -0.915em;
width: 3.66em;
height: 3.66em;
display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 3px 0 0;
-webkit-border-radius: 50%;
margin: 3px 0 0 0;
border-radius: 50%;
background-color: transparent
background-color: transparent;
}
/* Commenting this out - set by theme */
/*.emby-checkbox:focus + span + .emby-checkbox-focushelper {
background-color: rgba(82, 181, 75, 0.26);
}*/
.checkboxIcon {
font-size: 1.6em;
color: #fff
color: #fff;
}
.checkboxIcon-checked {
display: none
display: none;
}
.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-checked {
display: -webkit-box !important;
display: -webkit-flex !important;
display: flex !important
.emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-checked {
/* background-color set by theme */
/*background-color: #52B54B;*/
display: flex !important;
}
.emby-checkbox:checked+span+span+.checkboxOutline>.checkboxIcon-unchecked {
display: none !important
.emby-checkbox:checked + span + span + .checkboxOutline > .checkboxIcon-unchecked {
/* background-color set by theme */
display: none !important;
}
.emby-checkbox:checked[disabled]+span+span+.checkboxOutline>.checkboxIcon {
background-color: rgba(0, 0, 0, .26)
.emby-checkbox:checked[disabled] + span + span + .checkboxOutline > .checkboxIcon {
background-color: rgba(0, 0, 0, 0.26);
}
.checkboxLabel {
position: relative;
margin: 0
margin: 0;
}
.checkboxList>.emby-checkbox-label {
display: -webkit-box;
display: -webkit-flex;
.checkboxList > .emby-checkbox-label {
display: flex;
margin: .5em 0
margin: .5em 0;
}
.checkboxList-verticalwrap {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-flex-wrap: wrap;
flex-wrap: wrap
flex-wrap: wrap;
}
.checkboxList-verticalwrap>.emby-checkbox-label {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
margin: .3em 0;
width: 12em
}
.checkboxList-verticalwrap > .emby-checkbox-label {
display: inline-flex;
margin: .3em 0 .3em 0;
width: 12em;
}
.checkboxList-paperList {
padding: 1em !important
padding: 1em !important;
}
.checkboxListLabel {
margin-bottom: .25em
margin-bottom: .25em;
}
@-webkit-keyframes repaintChrome {
from,
to {
padding: 0
from {
padding: 0;
}
}
to {
padding: 0;
}
}
@@ -1,55 +1,110 @@
define(["browser", "dom", "css!./emby-checkbox", "registerElement"], function(browser, dom) {
"use strict";
define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (browser, dom) {
'use strict';
var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) {
if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", {
bubbles: !0
})), !1
// Don't submit form on enter
if (e.keyCode === 13) {
e.preventDefault();
this.checked = !this.checked;
this.dispatchEvent(new CustomEvent('change', {
bubbles: true
}));
return false;
}
}
var enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false;
function forceRefresh(loading) {
var elem = this.parentNode;
elem.style.webkitAnimationName = "repaintChrome", elem.style.webkitAnimationDelay = !0 === loading ? "500ms" : "", elem.style.webkitAnimationDuration = "10ms", elem.style.webkitAnimationIterationCount = "1", setTimeout(function() {
elem.style.webkitAnimationName = ""
}, !0 === loading ? 520 : 20)
elem.style.webkitAnimationName = 'repaintChrome';
elem.style.webkitAnimationDelay = (loading === true ? '500ms' : '');
elem.style.webkitAnimationDuration = '10ms';
elem.style.webkitAnimationIterationCount = '1';
setTimeout(function () {
elem.style.webkitAnimationName = '';
}, (loading === true ? 520 : 20));
}
var EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype),
enableRefreshHack = !!(browser.tizen || browser.orsay || browser.operaTv || browser.web0s);
EmbyCheckboxPrototype.attachedCallback = function() {
if ("true" !== this.getAttribute("data-embycheckbox")) {
this.setAttribute("data-embycheckbox", "true"), this.classList.add("emby-checkbox");
var labelElement = this.parentNode;
labelElement.classList.add("emby-checkbox-label");
var labelTextElement = labelElement.querySelector("span"),
outlineClass = "checkboxOutline",
customClass = this.getAttribute("data-outlineclass");
customClass && (outlineClass += " " + customClass);
var checkedIcon = this.getAttribute("data-checkedicon") || "&#xE5CA;",
uncheckedIcon = this.getAttribute("data-uncheckedicon") || "",
checkHtml = '<i class="md-icon checkboxIcon checkboxIcon-checked">' + checkedIcon + "</i>",
uncheckedHtml = '<i class="md-icon checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + "</i>";
labelElement.insertAdjacentHTML("beforeend", '<span class="emby-checkbox-focushelper"></span><span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + "</span>"), labelTextElement.classList.add("checkboxLabel"), this.addEventListener("keydown", onKeyDown), enableRefreshHack && (forceRefresh.call(this, !0), dom.addEventListener(this, "click", forceRefresh, {
passive: !0
}), dom.addEventListener(this, "blur", forceRefresh, {
passive: !0
}), dom.addEventListener(this, "focus", forceRefresh, {
passive: !0
}), dom.addEventListener(this, "change", forceRefresh, {
passive: !0
}))
EmbyCheckboxPrototype.attachedCallback = function () {
if (this.getAttribute('data-embycheckbox') === 'true') {
return;
}
}, EmbyCheckboxPrototype.detachedCallback = function() {
this.removeEventListener("keydown", onKeyDown), dom.removeEventListener(this, "click", forceRefresh, {
passive: !0
}), dom.removeEventListener(this, "blur", forceRefresh, {
passive: !0
}), dom.removeEventListener(this, "focus", forceRefresh, {
passive: !0
}), dom.removeEventListener(this, "change", forceRefresh, {
passive: !0
})
}, document.registerElement("emby-checkbox", {
this.setAttribute('data-embycheckbox', 'true');
this.classList.add('emby-checkbox');
var labelElement = this.parentNode;
labelElement.classList.add('emby-checkbox-label');
var labelTextElement = labelElement.querySelector('span');
var outlineClass = 'checkboxOutline';
var customClass = this.getAttribute('data-outlineclass');
if (customClass) {
outlineClass += ' ' + customClass;
}
var checkedIcon = this.getAttribute('data-checkedicon') || '&#xE5CA;';
var uncheckedIcon = this.getAttribute('data-uncheckedicon') || '';
var checkHtml = '<i class="md-icon checkboxIcon checkboxIcon-checked">' + checkedIcon + '</i>';
var uncheckedHtml = '<i class="md-icon checkboxIcon checkboxIcon-unchecked">' + uncheckedIcon + '</i>';
labelElement.insertAdjacentHTML('beforeend', '<span class="emby-checkbox-focushelper"></span><span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + '</span>');
labelTextElement.classList.add('checkboxLabel');
this.addEventListener('keydown', onKeyDown);
if (enableRefreshHack) {
forceRefresh.call(this, true);
dom.addEventListener(this, 'click', forceRefresh, {
passive: true
});
dom.addEventListener(this, 'blur', forceRefresh, {
passive: true
});
dom.addEventListener(this, 'focus', forceRefresh, {
passive: true
});
dom.addEventListener(this, 'change', forceRefresh, {
passive: true
});
}
};
EmbyCheckboxPrototype.detachedCallback = function () {
this.removeEventListener('keydown', onKeyDown);
dom.removeEventListener(this, 'click', forceRefresh, {
passive: true
});
dom.removeEventListener(this, 'blur', forceRefresh, {
passive: true
});
dom.removeEventListener(this, 'focus', forceRefresh, {
passive: true
});
dom.removeEventListener(this, 'change', forceRefresh, {
passive: true
});
};
document.registerElement('emby-checkbox', {
prototype: EmbyCheckboxPrototype,
extends: "input"
})
});
extends: 'input'
});
});
@@ -1,56 +1,44 @@
.emby-collapse {
margin: .5em 0
margin: .5em 0;
}
.collapseContent {
border-width: 0;
padding: 1.25em;
padding: 1.25em 1.25em;
height: 0;
-webkit-transition-property: height;
-o-transition-property: height;
transition-property: height;
-webkit-transition-duration: .3s;
-o-transition-duration: .3s;
transition-duration: .3s;
overflow: hidden
transition-duration: 300ms;
overflow: hidden;
}
.emby-collapsible-button {
margin: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
text-transform: none;
width: 100%;
text-align: left;
text-transform: none;
border-width: 0 0 .1em;
border-width: 0 0 .1em 0;
border-style: solid;
padding-left: .1em;
background: 0 0;
-webkit-box-shadow: none;
box-shadow: none
background: transparent;
box-shadow: none;
}
.emby-collapse-expandIcon {
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webkit-transition: -webkit-transform 180ms ease-out;
-o-transition: transform 180ms ease-out;
transition: transform 180ms ease-out;
position: absolute;
right: .5em;
font-size: 1.5em
font-size: 1.5em;
}
.emby-collapse-expandIconExpanded {
-webkit-transform: rotate(180deg);
transform: rotate(180deg)
transform: rotate(180deg);
}
.emby-collapsible-title {
margin: 0;
padding: 0
}
padding: 0;
}
@@ -1,43 +1,100 @@
define(["browser", "css!./emby-collapse", "registerElement", "emby-button"], function(browser) {
"use strict";
define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], function (browser) {
'use strict';
var EmbyButtonPrototype = Object.create(HTMLDivElement.prototype);
function slideDownToShow(button, elem) {
elem.classList.remove("hide"), elem.classList.add("expanded"), elem.style.height = "auto";
var height = elem.offsetHeight + "px";
elem.style.height = "0";
elem.offsetHeight;
elem.style.height = height, setTimeout(function() {
elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide"), elem.style.height = "auto"
}, 300), button.querySelector("i").classList.add("emby-collapse-expandIconExpanded")
elem.classList.remove('hide');
elem.classList.add('expanded');
elem.style.height = 'auto';
var height = elem.offsetHeight + 'px';
elem.style.height = '0';
// trigger reflow
var newHeight = elem.offsetHeight;
elem.style.height = height;
setTimeout(function () {
if (elem.classList.contains('expanded')) {
elem.classList.remove('hide');
} else {
elem.classList.add('hide');
}
elem.style.height = 'auto';
}, 300);
var icon = button.querySelector('i');
//icon.innerHTML = 'expand_less';
icon.classList.add('emby-collapse-expandIconExpanded');
}
function slideUpToHide(button, elem) {
elem.style.height = elem.offsetHeight + "px";
elem.offsetHeight;
elem.classList.remove("expanded"), elem.style.height = "0", setTimeout(function() {
elem.classList.contains("expanded") ? elem.classList.remove("hide") : elem.classList.add("hide")
}, 300), button.querySelector("i").classList.remove("emby-collapse-expandIconExpanded")
elem.style.height = elem.offsetHeight + 'px';
// trigger reflow
var newHeight = elem.offsetHeight;
elem.classList.remove('expanded');
elem.style.height = '0';
setTimeout(function () {
if (elem.classList.contains('expanded')) {
elem.classList.remove('hide');
} else {
elem.classList.add('hide');
}
}, 300);
var icon = button.querySelector('i');
//icon.innerHTML = 'expand_more';
icon.classList.remove('emby-collapse-expandIconExpanded');
}
function onButtonClick(e) {
var button = this,
collapseContent = button.parentNode.querySelector(".collapseContent");
collapseContent.expanded ? (collapseContent.expanded = !1, slideUpToHide(button, collapseContent)) : (collapseContent.expanded = !0, slideDownToShow(button, collapseContent))
}
var EmbyButtonPrototype = Object.create(HTMLDivElement.prototype);
EmbyButtonPrototype.attachedCallback = function() {
if (!this.classList.contains("emby-collapse")) {
this.classList.add("emby-collapse");
var collapseContent = this.querySelector(".collapseContent");
collapseContent && collapseContent.classList.add("hide");
var title = this.getAttribute("title"),
html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><i class="md-icon emby-collapse-expandIcon">expand_more</i></button>';
this.insertAdjacentHTML("afterbegin", html);
var button = this.querySelector(".emby-collapsible-button");
button.addEventListener("click", onButtonClick), "true" === this.getAttribute("data-expanded") && onButtonClick.call(button)
var button = this;
var collapseContent = button.parentNode.querySelector('.collapseContent');
if (collapseContent.expanded) {
collapseContent.expanded = false;
slideUpToHide(button, collapseContent);
} else {
collapseContent.expanded = true;
slideDownToShow(button, collapseContent);
}
}, document.registerElement("emby-collapse", {
}
EmbyButtonPrototype.attachedCallback = function () {
if (this.classList.contains('emby-collapse')) {
return;
}
this.classList.add('emby-collapse');
var collapseContent = this.querySelector('.collapseContent');
if (collapseContent) {
collapseContent.classList.add('hide');
}
var title = this.getAttribute('title');
var html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><i class="md-icon emby-collapse-expandIcon">expand_more</i></button>';
this.insertAdjacentHTML('afterbegin', html);
var button = this.querySelector('.emby-collapsible-button');
button.addEventListener('click', onButtonClick);
if (this.getAttribute('data-expanded') === 'true') {
onButtonClick.call(button);
}
};
document.registerElement('emby-collapse', {
prototype: EmbyButtonPrototype,
extends: "div"
})
extends: 'div'
});
});
@@ -1,106 +1,219 @@
define(["globalize", "apphost", "loading", "alert", "emby-linkbutton"], function(globalize, appHost, loading, alert) {
"use strict";
define(['globalize', 'apphost', 'loading', 'alert', 'emby-linkbutton'], function (globalize, appHost, loading, alert) {
'use strict';
function resolvePromise() {
return Promise.resolve()
return Promise.resolve();
}
function rejectPromise() {
return Promise.reject()
return Promise.reject();
}
function showNewUserInviteMessage(result) {
if (!result.IsNewUserInvitation && !result.IsPending) return Promise.resolve();
var message = result.IsNewUserInvitation ? globalize.translate("sharedcomponents#MessageInvitationSentToNewUser", result.GuestDisplayName) : globalize.translate("sharedcomponents#MessageInvitationSentToUser", result.GuestDisplayName);
if (!result.IsNewUserInvitation && !result.IsPending) {
// It was immediately approved
return Promise.resolve();
}
var message = result.IsNewUserInvitation ?
globalize.translate('sharedcomponents#MessageInvitationSentToNewUser', result.GuestDisplayName) :
globalize.translate('sharedcomponents#MessageInvitationSentToUser', result.GuestDisplayName);
return alert({
text: message,
title: globalize.translate("sharedcomponents#HeaderInvitationSent")
}).then(resolvePromise, resolvePromise)
title: globalize.translate('sharedcomponents#HeaderInvitationSent')
}).then(resolvePromise, resolvePromise);
}
function inviteGuest(options) {
var apiClient = options.apiClient;
return loading.show(), apiClient.ajax({
loading.show();
// Add/Update connect info
return apiClient.ajax({
type: "POST",
url: apiClient.getUrl("Connect/Invite"),
dataType: "json",
url: apiClient.getUrl('Connect/Invite'),
dataType: 'json',
data: options.guestOptions || {}
}).then(function(result) {
return loading.hide(), showNewUserInviteMessage(result)
}, function(response) {
}).then(function (result) {
loading.hide();
return showNewUserInviteMessage(result);
}, function (response) {
loading.hide();
var statusCode = response ? response.status : 0;
return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise) : 404 === statusCode ? alert({
text: globalize.translate("sharedcomponents#GuestUserNotFound")
}).then(rejectPromise, rejectPromise) : (statusCode || 0) >= 500 ? alert({
text: globalize.translate("sharedcomponents#ErrorReachingEmbyConnect")
}).then(rejectPromise, rejectPromise) : showGuestGeneralErrorMessage().then(rejectPromise, rejectPromise)
})
if (statusCode === 502) {
return showConnectServerUnreachableErrorMessage().then(rejectPromise, rejectPromise);
}
else if (statusCode === 404) {
// User doesn't exist
return alert({
text: globalize.translate('sharedcomponents#GuestUserNotFound')
}).then(rejectPromise, rejectPromise);
} else if ((statusCode || 0) >= 500) {
// Unable to reach connect server ?
return alert({
text: globalize.translate('sharedcomponents#ErrorReachingEmbyConnect')
}).then(rejectPromise, rejectPromise);
} else {
// status 400 = account not activated
// General error
return showGuestGeneralErrorMessage().then(rejectPromise, rejectPromise);
}
});
}
function showGuestGeneralErrorMessage() {
var html;
appHost.supports("externallinks") && (html = globalize.translate("sharedcomponents#ErrorAddingGuestAccount1", '<a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">https://github.com/jellyfin/jellyfin</a>'), html += "<br/><br/>" + globalize.translate("sharedcomponents#ErrorAddingGuestAccount2", "apps@emby.media"));
var text = globalize.translate("sharedcomponents#ErrorAddingGuestAccount1", "https://github.com/jellyfin/jellyfin");
return text += "\n\n" + globalize.translate("sharedcomponents#ErrorAddingGuestAccount2", "apps@emby.media"), alert({
if (appHost.supports('externallinks')) {
html = globalize.translate('sharedcomponents#ErrorAddingGuestAccount1', '<a is="emby-linkbutton" class="button-link" href="https://emby.media/connect" target="_blank">https://emby.media/connect</a>');
html += '<br/><br/>' + globalize.translate('sharedcomponents#ErrorAddingGuestAccount2', 'apps@emby.media');
}
var text = globalize.translate('sharedcomponents#ErrorAddingGuestAccount1', 'https://emby.media/connect');
text += '\n\n' + globalize.translate('sharedcomponents#ErrorAddingGuestAccount2', 'apps@emby.media');
return alert({
text: text,
html: html
})
});
}
function showConnectServerUnreachableErrorMessage() {
var text = globalize.translate("sharedcomponents#ErrorConnectServerUnreachable", "https://connect.emby.media");
var text = globalize.translate('sharedcomponents#ErrorConnectServerUnreachable', 'https://connect.emby.media');
return alert({
text: text
})
});
}
function showLinkUserErrorMessage(username, statusCode) {
var html, text;
return 502 === statusCode ? showConnectServerUnreachableErrorMessage() : (username ? (appHost.supports("externallinks") && (html = globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount1", '<a is="emby-linkbutton" class="button-link" href="https://github.com/jellyfin/jellyfin" target="_blank">https://github.com/jellyfin/jellyfin</a>'), html += "<br/><br/>" + globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount2", "apps@emby.media")), text = globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount1", "https://github.com/jellyfin/jellyfin"), text += "\n\n" + globalize.translate("sharedcomponents#ErrorAddingEmbyConnectAccount2", "apps@emby.media")) : html = text = globalize.translate("sharedcomponents#DefaultErrorMessage"), alert({
var html;
var text;
if (statusCode === 502) {
return showConnectServerUnreachableErrorMessage();
}
else if (username) {
if (appHost.supports('externallinks')) {
html = globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount1', '<a is="emby-linkbutton" class="button-link" href="https://emby.media/connect" target="_blank">https://emby.media/connect</a>');
html += '<br/><br/>' + globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount2', 'apps@emby.media');
}
text = globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount1', 'https://emby.media/connect');
text += '\n\n' + globalize.translate('sharedcomponents#ErrorAddingEmbyConnectAccount2', 'apps@emby.media');
} else {
html = text = globalize.translate('sharedcomponents#DefaultErrorMessage');
}
return alert({
text: text,
html: html
}))
});
}
function updateUserLink(apiClient, user, newConnectUsername) {
var currentConnectUsername = user.ConnectUserName || "",
enteredConnectUsername = newConnectUsername,
linkUrl = apiClient.getUrl("Users/" + user.Id + "/Connect/Link");
return currentConnectUsername && !enteredConnectUsername ? apiClient.ajax({
type: "DELETE",
url: linkUrl
}).then(function() {
return alert({
text: globalize.translate("sharedcomponents#MessageEmbyAccontRemoved"),
title: globalize.translate("sharedcomponents#HeaderEmbyAccountRemoved")
}).catch(resolvePromise)
}, function(response) {
return 502 === (response ? response.status : 0) ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : alert({
text: globalize.translate("sharedcomponents#ErrorRemovingEmbyConnectAccount")
}).then(rejectPromise)
}) : currentConnectUsername !== enteredConnectUsername ? apiClient.ajax({
type: "POST",
url: linkUrl,
data: {
ConnectUsername: enteredConnectUsername
},
dataType: "json"
}).then(function(result) {
var msgKey = result.IsPending ? "sharedcomponents#MessagePendingEmbyAccountAdded" : "sharedcomponents#MessageEmbyAccountAdded";
return alert({
text: globalize.translate(msgKey),
title: globalize.translate("sharedcomponents#HeaderEmbyAccountAdded")
}).catch(resolvePromise)
}, function(response) {
var statusCode = response ? response.status : 0;
return 502 === statusCode ? showConnectServerUnreachableErrorMessage().then(rejectPromise) : showLinkUserErrorMessage(".", statusCode).then(rejectPromise)
}) : Promise.reject()
var currentConnectUsername = user.ConnectUserName || '';
var enteredConnectUsername = newConnectUsername;
var linkUrl = apiClient.getUrl('Users/' + user.Id + '/Connect/Link');
if (currentConnectUsername && !enteredConnectUsername) {
// Remove connect info
// Add/Update connect info
return apiClient.ajax({
type: "DELETE",
url: linkUrl
}).then(function () {
return alert({
text: globalize.translate('sharedcomponents#MessageEmbyAccontRemoved'),
title: globalize.translate('sharedcomponents#HeaderEmbyAccountRemoved'),
}).catch(resolvePromise);
}, function (response) {
var statusCode = response ? response.status : 0;
if (statusCode === 502) {
return showConnectServerUnreachableErrorMessage().then(rejectPromise);
}
return alert({
text: globalize.translate('sharedcomponents#ErrorRemovingEmbyConnectAccount')
}).then(rejectPromise);
});
}
else if (currentConnectUsername !== enteredConnectUsername) {
// Add/Update connect info
return apiClient.ajax({
type: "POST",
url: linkUrl,
data: {
ConnectUsername: enteredConnectUsername
},
dataType: 'json'
}).then(function (result) {
var msgKey = result.IsPending ? 'sharedcomponents#MessagePendingEmbyAccountAdded' : 'sharedcomponents#MessageEmbyAccountAdded';
return alert({
text: globalize.translate(msgKey),
title: globalize.translate('sharedcomponents#HeaderEmbyAccountAdded'),
}).catch(resolvePromise);
}, function (response) {
var statusCode = response ? response.status : 0;
if (statusCode === 502) {
return showConnectServerUnreachableErrorMessage().then(rejectPromise);
}
return showLinkUserErrorMessage('.', statusCode).then(rejectPromise);
});
} else {
return Promise.reject();
}
}
return {
inviteGuest: inviteGuest,
updateUserLink: updateUserLink,
showLinkUserErrorMessage: showLinkUserErrorMessage,
showConnectServerUnreachableErrorMessage: showConnectServerUnreachableErrorMessage
}
};
});
@@ -2,35 +2,39 @@
display: block;
margin: 0;
margin-bottom: 0 !important;
/* Remove select styling */
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
font-size: 110%;
/* General select styles: change as needed */
font-family: inherit;
font-weight: inherit;
padding: .4em .25em;
/* Prevent padding from causing width overflow */
-webkit-box-sizing: border-box;
box-sizing: border-box;
outline: 0 !important;
-webkit-tap-highlight-color: transparent;
width: 100%
outline: none !important;
-webkit-tap-highlight-color: rgba(0,0,0,0);
width: 100%;
}
.emby-input::-moz-focus-inner {
border: 0
}
.emby-input::-moz-focus-inner {
border: 0;
}
.inputContainer {
margin-bottom: 1.8em
margin-bottom: 1.8em;
}
.inputLabel {
display: inline-block;
margin-bottom: .25em
margin-bottom: .25em;
}
.emby-input+.fieldDescription {
margin-top: .25em
.emby-input + .fieldDescription {
margin-top: .25em;
}
.emby-input-iconbutton {
-webkit-align-self: flex-end;
align-self: flex-end
}
align-self: flex-end;
}
@@ -1,56 +1,125 @@
define(["layoutManager", "browser", "dom", "css!./emby-input", "registerElement"], function(layoutManager, browser, dom) {
"use strict";
define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement'], function (layoutManager, browser, dom) {
'use strict';
var EmbyInputPrototype = Object.create(HTMLInputElement.prototype);
var inputId = 0;
var supportsFloatingLabel = false;
function onChange() {
var label = this.labelElement;
if (this.value) label.classList.remove("inputLabel-float");
else {
supportsFloatingLabel && "date" !== this.type && "time" !== this.type && label.classList.add("inputLabel-float")
}
}
var EmbyInputPrototype = Object.create(HTMLInputElement.prototype),
inputId = 0,
supportsFloatingLabel = !1;
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
// descriptor returning null in webos
if (descriptor && descriptor.configurable) {
var baseSetMethod = descriptor.set;
descriptor.set = function(value) {
baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", {
bubbles: !1,
cancelable: !1
}))
}, Object.defineProperty(HTMLInputElement.prototype, "value", descriptor), supportsFloatingLabel = !0
descriptor.set = function (value) {
baseSetMethod.call(this, value);
this.dispatchEvent(new CustomEvent('valueset', {
bubbles: false,
cancelable: false
}));
};
Object.defineProperty(HTMLInputElement.prototype, 'value', descriptor);
supportsFloatingLabel = true;
}
}
EmbyInputPrototype.createdCallback = function() {
if (this.id || (this.id = "embyinput" + inputId, inputId++), !this.classList.contains("emby-input")) {
this.classList.add("emby-input");
var parentNode = this.parentNode,
document = this.ownerDocument,
label = document.createElement("label");
label.innerHTML = this.getAttribute("label") || "", label.classList.add("inputLabel"), label.classList.add("inputLabelUnfocused"), label.htmlFor = this.id, parentNode.insertBefore(label, this), this.labelElement = label, dom.addEventListener(this, "focus", function() {
onChange.call(this), document.attachIME && document.attachIME(this), label.classList.add("inputLabelFocused"), label.classList.remove("inputLabelUnfocused")
}, {
passive: !0
}), dom.addEventListener(this, "blur", function() {
onChange.call(this), label.classList.remove("inputLabelFocused"), label.classList.add("inputLabelUnfocused")
}, {
passive: !0
}), dom.addEventListener(this, "change", onChange, {
passive: !0
}), dom.addEventListener(this, "input", onChange, {
passive: !0
}), dom.addEventListener(this, "valueset", onChange, {
passive: !0
}), browser.orsay && this === document.activeElement && document.attachIME && document.attachIME(this)
EmbyInputPrototype.createdCallback = function () {
if (!this.id) {
this.id = 'embyinput' + inputId;
inputId++;
} if (this.classList.contains('emby-input')) {
return;
}
}, EmbyInputPrototype.attachedCallback = function() {
this.labelElement.htmlFor = this.id, onChange.call(this)
}, EmbyInputPrototype.label = function(text) {
this.labelElement.innerHTML = text
}, document.registerElement("emby-input", {
this.classList.add('emby-input');
var parentNode = this.parentNode;
var document = this.ownerDocument;
var label = document.createElement('label');
label.innerHTML = this.getAttribute('label') || '';
label.classList.add('inputLabel');
label.classList.add('inputLabelUnfocused');
label.htmlFor = this.id;
parentNode.insertBefore(label, this);
this.labelElement = label;
dom.addEventListener(this, 'focus', function () {
onChange.call(this);
// For Samsung orsay devices
if (document.attachIME) {
document.attachIME(this);
}
label.classList.add('inputLabelFocused');
label.classList.remove('inputLabelUnfocused');
}, {
passive: true
});
dom.addEventListener(this, 'blur', function () {
onChange.call(this);
label.classList.remove('inputLabelFocused');
label.classList.add('inputLabelUnfocused');
}, {
passive: true
});
dom.addEventListener(this, 'change', onChange, {
passive: true
});
dom.addEventListener(this, 'input', onChange, {
passive: true
});
dom.addEventListener(this, 'valueset', onChange, {
passive: true
});
if (browser.orsay) {
if (this === document.activeElement) {
//Make sure the IME pops up if this is the first/default element on the page
if (document.attachIME) {
document.attachIME(this);
}
}
}
};
function onChange() {
var label = this.labelElement;
if (this.value) {
label.classList.remove('inputLabel-float');
} else {
var instanceSupportsFloat = supportsFloatingLabel && this.type !== 'date' && this.type !== 'time';
if (instanceSupportsFloat) {
label.classList.add('inputLabel-float');
}
}
}
EmbyInputPrototype.attachedCallback = function () {
this.labelElement.htmlFor = this.id;
onChange.call(this);
};
EmbyInputPrototype.label = function (text) {
this.labelElement.innerHTML = text;
};
document.registerElement('emby-input', {
prototype: EmbyInputPrototype,
extends: "input"
})
extends: 'input'
});
});
@@ -1,32 +1,77 @@
define(["emby-progressring", "dom", "serverNotifications", "events", "registerElement"], function(EmbyProgressRing, dom, serverNotifications, events) {
"use strict";
define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'registerElement'], function (EmbyProgressRing, dom, serverNotifications, events) {
'use strict';
function addNotificationEvent(instance, name, handler) {
var localHandler = handler.bind(instance);
events.on(serverNotifications, name, localHandler), instance[name] = localHandler
events.on(serverNotifications, name, localHandler);
instance[name] = localHandler;
}
function removeNotificationEvent(instance, name) {
var handler = instance[name];
handler && (events.off(serverNotifications, name, handler), instance[name] = null)
if (handler) {
events.off(serverNotifications, name, handler);
instance[name] = null;
}
}
function onRefreshProgress(e, apiClient, info) {
var indicator = this;
if (indicator.itemId || (indicator.itemId = dom.parentWithAttribute(indicator, "data-id").getAttribute("data-id")), info.ItemId === indicator.itemId) {
if (!indicator.itemId) {
indicator.itemId = dom.parentWithAttribute(indicator, 'data-id').getAttribute('data-id');
}
if (info.ItemId === indicator.itemId) {
var progress = parseFloat(info.Progress);
progress && progress < 100 ? this.classList.remove("hide") : this.classList.add("hide"), this.setProgress(progress)
if (progress && progress < 100) {
this.classList.remove('hide');
} else {
this.classList.add('hide');
}
this.setProgress(progress);
}
}
var EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
EmbyItemRefreshIndicatorPrototype.createdCallback = function() {
EmbyProgressRing.createdCallback && EmbyProgressRing.createdCallback.call(this), addNotificationEvent(this, "RefreshProgress", onRefreshProgress)
}, EmbyItemRefreshIndicatorPrototype.attachedCallback = function() {
EmbyProgressRing.attachedCallback && EmbyProgressRing.attachedCallback.call(this)
}, EmbyItemRefreshIndicatorPrototype.detachedCallback = function() {
EmbyProgressRing.detachedCallback && EmbyProgressRing.detachedCallback.call(this), removeNotificationEvent(this, "RefreshProgress"), this.itemId = null
}, document.registerElement("emby-itemrefreshindicator", {
EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
// base method
if (EmbyProgressRing.createdCallback) {
EmbyProgressRing.createdCallback.call(this);
}
addNotificationEvent(this, 'RefreshProgress', onRefreshProgress);
};
EmbyItemRefreshIndicatorPrototype.attachedCallback = function () {
// base method
if (EmbyProgressRing.attachedCallback) {
EmbyProgressRing.attachedCallback.call(this);
}
};
EmbyItemRefreshIndicatorPrototype.detachedCallback = function () {
// base method
if (EmbyProgressRing.detachedCallback) {
EmbyProgressRing.detachedCallback.call(this);
}
removeNotificationEvent(this, 'RefreshProgress');
this.itemId = null;
};
document.registerElement('emby-itemrefreshindicator', {
prototype: EmbyItemRefreshIndicatorPrototype,
extends: "div"
})
extends: 'div'
});
});
@@ -1,220 +1,548 @@
define(["itemShortcuts", "inputManager", "connectionManager", "playbackManager", "imageLoader", "layoutManager", "browser", "dom", "loading", "focusManager", "serverNotifications", "events", "registerElement"], function(itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) {
"use strict";
define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', 'imageLoader', 'layoutManager', 'browser', 'dom', 'loading', 'focusManager', 'serverNotifications', 'events', 'registerElement'], function (itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) {
'use strict';
var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype);
function onClick(e) {
var itemsContainer = this,
multiSelect = (e.target, itemsContainer.multiSelect);
multiSelect && !1 === multiSelect.onContainerClick.call(itemsContainer, e) || itemShortcuts.onClick.call(itemsContainer, e)
var itemsContainer = this;
var target = e.target;
var multiSelect = itemsContainer.multiSelect;
if (multiSelect) {
if (multiSelect.onContainerClick.call(itemsContainer, e) === false) {
return;
}
}
itemShortcuts.onClick.call(itemsContainer, e);
}
function disableEvent(e) {
return e.preventDefault(), e.stopPropagation(), !1
e.preventDefault();
e.stopPropagation();
return false;
}
function onContextMenu(e) {
var target = e.target,
card = dom.parentWithAttribute(target, "data-id");
if (card && card.getAttribute("data-serverid")) return inputManager.trigger("menu", {
sourceElement: card
}), e.preventDefault(), e.stopPropagation(), !1
var itemsContainer = this;
var target = e.target;
var card = dom.parentWithAttribute(target, 'data-id');
// check for serverId, it won't be present on selectserver
if (card && card.getAttribute('data-serverid')) {
inputManager.trigger('menu', {
sourceElement: card
});
e.preventDefault();
e.stopPropagation();
return false;
}
}
function getShortcutOptions() {
return {
click: !1
}
click: false
};
}
ItemsContainerProtoType.enableMultiSelect = function (enabled) {
var current = this.multiSelect;
if (!enabled) {
if (current) {
current.destroy();
this.multiSelect = null;
}
return;
}
if (current) {
return;
}
var self = this;
require(['multiSelect'], function (MultiSelect) {
self.multiSelect = new MultiSelect({
container: self,
bindOnClick: false
});
});
};
function onDrop(evt, itemsContainer) {
var el = evt.item,
newIndex = evt.newIndex,
itemId = el.getAttribute("data-playlistitemid"),
playlistId = el.getAttribute("data-playlistid");
var el = evt.item;
var newIndex = evt.newIndex;
var itemId = el.getAttribute('data-playlistitemid');
var playlistId = el.getAttribute('data-playlistid');
if (!playlistId) {
var oldIndex = evt.oldIndex;
return void el.dispatchEvent(new CustomEvent("itemdrop", {
el.dispatchEvent(new CustomEvent('itemdrop', {
detail: {
oldIndex: oldIndex,
newIndex: newIndex,
playlistItemId: itemId
},
bubbles: !0,
cancelable: !1
}))
bubbles: true,
cancelable: false
}));
return;
}
var serverId = el.getAttribute("data-serverid"),
apiClient = connectionManager.getApiClient(serverId);
loading.show(), apiClient.ajax({
url: apiClient.getUrl("Playlists/" + playlistId + "/Items/" + itemId + "/Move/" + newIndex),
type: "POST"
}).then(function() {
loading.hide()
}, function() {
loading.hide(), itemsContainer.refreshItems()
})
var serverId = el.getAttribute('data-serverid');
var apiClient = connectionManager.getApiClient(serverId);
loading.show();
apiClient.ajax({
url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex),
type: 'POST'
}).then(function () {
loading.hide();
}, function () {
loading.hide();
itemsContainer.refreshItems();
});
}
function onUserDataChanged(e, apiClient, userData) {
var itemsContainer = this;
require(["cardBuilder"], function(cardBuilder) {
cardBuilder.onUserDataChanged(userData, itemsContainer)
ItemsContainerProtoType.enableDragReordering = function (enabled) {
var current = this.sortable;
if (!enabled) {
if (current) {
current.destroy();
this.sortable = null;
}
return;
}
if (current) {
return;
}
var self = this;
require(['sortable'], function (Sortable) {
self.sortable = new Sortable(self, {
draggable: ".listItem",
handle: '.listViewDragHandle',
// dragging ended
onEnd: function (/**Event*/evt) {
return onDrop(evt, self);
}
});
});
var eventsToMonitor = getEventsToMonitor(itemsContainer); - 1 !== eventsToMonitor.indexOf("markfavorite") ? itemsContainer.notifyRefreshNeeded() : -1 !== eventsToMonitor.indexOf("markplayed") && itemsContainer.notifyRefreshNeeded()
};
function onUserDataChanged(e, apiClient, userData) {
var itemsContainer = this;
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onUserDataChanged(userData, itemsContainer);
});
var eventsToMonitor = getEventsToMonitor(itemsContainer);
// TODO: Check user data change reason?
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
itemsContainer.notifyRefreshNeeded();
}
else if (eventsToMonitor.indexOf('markplayed') !== -1) {
itemsContainer.notifyRefreshNeeded();
}
}
function getEventsToMonitor(itemsContainer) {
var monitor = itemsContainer.getAttribute("data-monitor");
return monitor ? monitor.split(",") : []
var monitor = itemsContainer.getAttribute('data-monitor');
if (monitor) {
return monitor.split(',');
}
return [];
}
function onTimerCreated(e, apiClient, data) {
var itemsContainer = this;
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("timers")) return void itemsContainer.notifyRefreshNeeded();
var programId = data.ProgramId,
newTimerId = data.Id;
require(["cardBuilder"], function(cardBuilder) {
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer)
})
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
var programId = data.ProgramId;
// This could be null, not supported by all tv providers
var newTimerId = data.Id;
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer);
});
}
function onSeriesTimerCreated(e, apiClient, data) {
var itemsContainer = this;
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("seriestimers")) return void itemsContainer.notifyRefreshNeeded()
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
}
function onTimerCancelled(e, apiClient, data) {
var itemsContainer = this;
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("timers")) return void itemsContainer.notifyRefreshNeeded();
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
var id = data.Id;
require(["cardBuilder"], function(cardBuilder) {
cardBuilder.onTimerCancelled(id, itemsContainer)
})
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onTimerCancelled(id, itemsContainer);
});
}
function onSeriesTimerCancelled(e, apiClient, data) {
var itemsContainer = this;
if (-1 !== getEventsToMonitor(itemsContainer).indexOf("seriestimers")) return void itemsContainer.notifyRefreshNeeded();
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
itemsContainer.notifyRefreshNeeded();
return;
}
var id = data.Id;
require(["cardBuilder"], function(cardBuilder) {
cardBuilder.onSeriesTimerCancelled(id, itemsContainer)
})
require(['cardBuilder'], function (cardBuilder) {
cardBuilder.onSeriesTimerCancelled(id, itemsContainer);
});
}
function onLibraryChanged(e, apiClient, data) {
var itemsContainer = this,
eventsToMonitor = getEventsToMonitor(itemsContainer);
if (-1 === eventsToMonitor.indexOf("seriestimers") && -1 === eventsToMonitor.indexOf("timers")) {
var itemsAdded = data.ItemsAdded || [],
itemsRemoved = data.ItemsRemoved || [];
if (itemsAdded.length || itemsRemoved.length) {
var parentId = itemsContainer.getAttribute("data-parentid");
if (parentId) {
var foldersAddedTo = data.FoldersAddedTo || [],
foldersRemovedFrom = data.FoldersRemovedFrom || [],
collectionFolders = data.CollectionFolders || [];
if (-1 === foldersAddedTo.indexOf(parentId) && -1 === foldersRemovedFrom.indexOf(parentId) && -1 === collectionFolders.indexOf(parentId)) return
}
itemsContainer.notifyRefreshNeeded()
var itemsContainer = this;
var eventsToMonitor = getEventsToMonitor(itemsContainer);
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
// yes this is an assumption
return;
}
var itemsAdded = data.ItemsAdded || [];
var itemsRemoved = data.ItemsRemoved || [];
if (!itemsAdded.length && !itemsRemoved.length) {
return;
}
var parentId = itemsContainer.getAttribute('data-parentid');
if (parentId) {
var foldersAddedTo = data.FoldersAddedTo || [];
var foldersRemovedFrom = data.FoldersRemovedFrom || [];
var collectionFolders = data.CollectionFolders || [];
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
return;
}
}
itemsContainer.notifyRefreshNeeded();
}
function onPlaybackStopped(e, stopInfo) {
var itemsContainer = this;
var state = stopInfo.state;
var eventsToMonitor = getEventsToMonitor(itemsContainer);
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
itemsContainer.notifyRefreshNeeded(true);
return;
}
}
else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
itemsContainer.notifyRefreshNeeded(true);
return;
}
}
}
function onPlaybackStopped(e, stopInfo) {
var itemsContainer = this,
state = stopInfo.state,
eventsToMonitor = getEventsToMonitor(itemsContainer);
if (state.NowPlayingItem && "Video" === state.NowPlayingItem.MediaType) {
if (-1 !== eventsToMonitor.indexOf("videoplayback")) return void itemsContainer.notifyRefreshNeeded(!0)
} else if (state.NowPlayingItem && "Audio" === state.NowPlayingItem.MediaType && -1 !== eventsToMonitor.indexOf("audioplayback")) return void itemsContainer.notifyRefreshNeeded(!0)
}
function addNotificationEvent(instance, name, handler, owner) {
var localHandler = handler.bind(instance);
owner = owner || serverNotifications, events.on(owner, name, localHandler), instance["event_" + name] = localHandler
owner = owner || serverNotifications;
events.on(owner, name, localHandler);
instance['event_' + name] = localHandler;
}
function removeNotificationEvent(instance, name, owner) {
var handler = instance["event_" + name];
handler && (owner = owner || serverNotifications, events.off(owner, name, handler), instance["event_" + name] = null)
var handler = instance['event_' + name];
if (handler) {
owner = owner || serverNotifications;
events.off(owner, name, handler);
instance['event_' + name] = null;
}
}
ItemsContainerProtoType.createdCallback = function () {
this.classList.add('itemsContainer');
};
ItemsContainerProtoType.attachedCallback = function () {
this.addEventListener('click', onClick);
if (browser.touch) {
this.addEventListener('contextmenu', disableEvent);
} else {
if (this.getAttribute('data-contextmenu') !== 'false') {
this.addEventListener('contextmenu', onContextMenu);
}
}
if (layoutManager.desktop || layoutManager.mobile) {
if (this.getAttribute('data-multiselect') !== 'false') {
this.enableMultiSelect(true);
}
}
if (layoutManager.tv) {
this.classList.add('itemsContainer-tv');
}
itemShortcuts.on(this, getShortcutOptions());
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
addNotificationEvent(this, 'TimerCreated', onTimerCreated);
addNotificationEvent(this, 'SeriesTimerCreated', onSeriesTimerCreated);
addNotificationEvent(this, 'TimerCancelled', onTimerCancelled);
addNotificationEvent(this, 'SeriesTimerCancelled', onSeriesTimerCancelled);
addNotificationEvent(this, 'LibraryChanged', onLibraryChanged);
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
if (this.getAttribute('data-dragreorder') === 'true') {
this.enableDragReordering(true);
}
};
ItemsContainerProtoType.detachedCallback = function () {
clearRefreshInterval(this);
this.enableMultiSelect(false);
this.enableDragReordering(false);
this.removeEventListener('click', onClick);
this.removeEventListener('contextmenu', onContextMenu);
this.removeEventListener('contextmenu', disableEvent);
itemShortcuts.off(this, getShortcutOptions());
removeNotificationEvent(this, 'UserDataChanged');
removeNotificationEvent(this, 'TimerCreated');
removeNotificationEvent(this, 'SeriesTimerCreated');
removeNotificationEvent(this, 'TimerCancelled');
removeNotificationEvent(this, 'SeriesTimerCancelled');
removeNotificationEvent(this, 'LibraryChanged');
removeNotificationEvent(this, 'playbackstop', playbackManager);
this.fetchData = null;
this.getItemsHtml = null;
this.parentContainer = null;
};
ItemsContainerProtoType.pause = function () {
clearRefreshInterval(this, true);
this.paused = true;
};
ItemsContainerProtoType.resume = function (options) {
this.paused = false;
var refreshIntervalEndTime = this.refreshIntervalEndTime;
if (refreshIntervalEndTime) {
var remainingMs = refreshIntervalEndTime - new Date().getTime();
if (remainingMs > 0 && !this.needsRefresh) {
resetRefreshInterval(this, remainingMs);
} else {
this.needsRefresh = true;
this.refreshIntervalEndTime = null;
}
}
if (this.needsRefresh || (options && options.refresh)) {
return this.refreshItems();
}
return Promise.resolve();
};
ItemsContainerProtoType.refreshItems = function () {
if (!this.fetchData) {
return Promise.resolve();
}
if (this.paused) {
this.needsRefresh = true;
return Promise.resolve();
}
this.needsRefresh = false;
return this.fetchData().then(onDataFetched.bind(this));
};
ItemsContainerProtoType.notifyRefreshNeeded = function (isInForeground) {
if (this.paused) {
this.needsRefresh = true;
return;
}
var timeout = this.refreshTimeout;
if (timeout) {
clearTimeout(timeout);
}
if (isInForeground === true) {
this.refreshItems();
} else {
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
}
};
function clearRefreshInterval(itemsContainer, isPausing) {
itemsContainer.refreshInterval && (clearInterval(itemsContainer.refreshInterval), itemsContainer.refreshInterval = null, isPausing || (itemsContainer.refreshIntervalEndTime = null))
if (itemsContainer.refreshInterval) {
clearInterval(itemsContainer.refreshInterval);
itemsContainer.refreshInterval = null;
if (!isPausing) {
itemsContainer.refreshIntervalEndTime = null;
}
}
}
function resetRefreshInterval(itemsContainer, intervalMs) {
clearRefreshInterval(itemsContainer), intervalMs || (intervalMs = parseInt(itemsContainer.getAttribute("data-refreshinterval") || "0")), intervalMs && (itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs), itemsContainer.refreshIntervalEndTime = (new Date).getTime() + intervalMs)
clearRefreshInterval(itemsContainer);
if (!intervalMs) {
intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0');
}
if (intervalMs) {
itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs);
itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs;
}
}
function onDataFetched(result) {
var items = result.Items || result,
parentContainer = this.parentContainer;
parentContainer && (items.length ? parentContainer.classList.remove("hide") : parentContainer.classList.add("hide"));
var focusId, hasActiveElement, activeElement = document.activeElement;
this.contains(activeElement) && (hasActiveElement = !0, focusId = activeElement.getAttribute("data-id")), this.innerHTML = this.getItemsHtml(items), imageLoader.lazyChildren(this), hasActiveElement && setFocus(this, focusId), resetRefreshInterval(this), this.afterRefresh && this.afterRefresh(result)
var items = result.Items || result;
var parentContainer = this.parentContainer;
if (parentContainer) {
if (items.length) {
parentContainer.classList.remove('hide');
} else {
parentContainer.classList.add('hide');
}
}
// Scroll back up so they can see the results from the beginning
// TODO: Find scroller
//window.scrollTo(0, 0);
var activeElement = document.activeElement;
var focusId;
var hasActiveElement;
if (this.contains(activeElement)) {
hasActiveElement = true;
focusId = activeElement.getAttribute('data-id');
}
this.innerHTML = this.getItemsHtml(items);
imageLoader.lazyChildren(this);
if (hasActiveElement) {
setFocus(this, focusId);
}
resetRefreshInterval(this);
if (this.afterRefresh) {
this.afterRefresh(result);
}
}
function setFocus(itemsContainer, focusId) {
if (focusId) {
var newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]');
if (newElement) try {
return void focusManager.focus(newElement)
} catch (err) {}
if (newElement) {
try {
focusManager.focus(newElement);
return;
}
catch (err) {
}
}
}
focusManager.autoFocus(itemsContainer)
focusManager.autoFocus(itemsContainer);
}
var ItemsContainerProtoType = Object.create(HTMLDivElement.prototype);
ItemsContainerProtoType.enableMultiSelect = function(enabled) {
var current = this.multiSelect;
if (!enabled) return void(current && (current.destroy(), this.multiSelect = null));
if (!current) {
var self = this;
require(["multiSelect"], function(MultiSelect) {
self.multiSelect = new MultiSelect({
container: self,
bindOnClick: !1
})
})
}
}, ItemsContainerProtoType.enableDragReordering = function(enabled) {
var current = this.sortable;
if (!enabled) return void(current && (current.destroy(), this.sortable = null));
if (!current) {
var self = this;
require(["sortable"], function(Sortable) {
self.sortable = new Sortable(self, {
draggable: ".listItem",
handle: ".listViewDragHandle",
onEnd: function(evt) {
return onDrop(evt, self)
}
})
})
}
}, ItemsContainerProtoType.createdCallback = function() {
this.classList.add("itemsContainer")
}, ItemsContainerProtoType.attachedCallback = function() {
this.addEventListener("click", onClick), browser.touch ? this.addEventListener("contextmenu", disableEvent) : "false" !== this.getAttribute("data-contextmenu") && this.addEventListener("contextmenu", onContextMenu), (layoutManager.desktop || layoutManager.mobile) && "false" !== this.getAttribute("data-multiselect") && this.enableMultiSelect(!0), layoutManager.tv && this.classList.add("itemsContainer-tv"), itemShortcuts.on(this, getShortcutOptions()), addNotificationEvent(this, "UserDataChanged", onUserDataChanged), addNotificationEvent(this, "TimerCreated", onTimerCreated), addNotificationEvent(this, "SeriesTimerCreated", onSeriesTimerCreated), addNotificationEvent(this, "TimerCancelled", onTimerCancelled), addNotificationEvent(this, "SeriesTimerCancelled", onSeriesTimerCancelled), addNotificationEvent(this, "LibraryChanged", onLibraryChanged), addNotificationEvent(this, "playbackstop", onPlaybackStopped, playbackManager), "true" === this.getAttribute("data-dragreorder") && this.enableDragReordering(!0)
}, ItemsContainerProtoType.detachedCallback = function() {
clearRefreshInterval(this), this.enableMultiSelect(!1), this.enableDragReordering(!1), this.removeEventListener("click", onClick), this.removeEventListener("contextmenu", onContextMenu), this.removeEventListener("contextmenu", disableEvent), itemShortcuts.off(this, getShortcutOptions()), removeNotificationEvent(this, "UserDataChanged"), removeNotificationEvent(this, "TimerCreated"), removeNotificationEvent(this, "SeriesTimerCreated"), removeNotificationEvent(this, "TimerCancelled"), removeNotificationEvent(this, "SeriesTimerCancelled"), removeNotificationEvent(this, "LibraryChanged"), removeNotificationEvent(this, "playbackstop", playbackManager), this.fetchData = null, this.getItemsHtml = null, this.parentContainer = null
}, ItemsContainerProtoType.pause = function() {
clearRefreshInterval(this, !0), this.paused = !0
}, ItemsContainerProtoType.resume = function(options) {
this.paused = !1;
var refreshIntervalEndTime = this.refreshIntervalEndTime;
if (refreshIntervalEndTime) {
var remainingMs = refreshIntervalEndTime - (new Date).getTime();
remainingMs > 0 && !this.needsRefresh ? resetRefreshInterval(this, remainingMs) : (this.needsRefresh = !0, this.refreshIntervalEndTime = null)
}
return this.needsRefresh || options && options.refresh ? this.refreshItems() : Promise.resolve()
}, ItemsContainerProtoType.refreshItems = function() {
return this.fetchData ? this.paused ? (this.needsRefresh = !0, Promise.resolve()) : (this.needsRefresh = !1, this.fetchData().then(onDataFetched.bind(this))) : Promise.resolve()
}, ItemsContainerProtoType.notifyRefreshNeeded = function(isInForeground) {
if (this.paused) return void(this.needsRefresh = !0);
var timeout = this.refreshTimeout;
timeout && clearTimeout(timeout), !0 === isInForeground ? this.refreshItems() : this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 1e4)
}, document.registerElement("emby-itemscontainer", {
document.registerElement('emby-itemscontainer', {
prototype: ItemsContainerProtoType,
extends: "div"
})
extends: 'div'
});
});
@@ -1,157 +1,105 @@
.progressring {
.progressring {
position: relative;
width: 2.6em;
height: 2.6em;
float: left;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-box-sizing: border-box;
box-sizing: border-box
box-sizing: border-box;
}
.progressring-bg {
width: 100%;
height: 100%;
-webkit-border-radius: 50%;
border-radius: 50%;
border: .25em solid rgba(0, 0, 0, 1);
-webkit-box-sizing: border-box;
box-sizing: border-box;
background: rgba(0, 0, 0, .9);
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center
}
.spiner-holder-one,
.spiner-holder-two {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
background: 0 0;
-webkit-box-sizing: border-box
justify-content: center;
}
.progressring-text {
text-align: center;
color: #ddd;
font-size: 90%
font-size: 90%;
}
.spiner-holder-one {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
width: 51%;
height: 51%;
box-sizing: border-box
background: transparent;
box-sizing: border-box;
}
.spiner-holder-two {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
width: 100%;
height: 100%;
box-sizing: border-box
background: transparent;
box-sizing: border-box;
}
.progressring-spiner {
width: 200%;
height: 200%;
-webkit-border-radius: 50%;
border-radius: 50%;
border-width: .25em;
border-style: solid;
-webkit-box-sizing: border-box;
box-sizing: border-box
box-sizing: border-box;
}
.animate-0-25-a {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
-webkit-transition: -webkit-transform 180ms ease-out;
-o-transition: transform 180ms ease-out;
transition: transform 180ms ease-out
}
.animate-0-25-b,
.animate-25-50-a {
-webkit-transition: -webkit-transform 180ms ease-out;
-o-transition: transform 180ms ease-out
transition: transform 180ms ease-out;
}
.animate-0-25-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
transition: transform 180ms ease-out
transition: transform 180ms ease-out;
}
.animate-25-50-a {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
transition: transform 180ms ease-out
}
.animate-25-50-b,
.animate-50-75-a {
-webkit-transition: -webkit-transform 180ms ease-out;
-o-transition: transform 180ms ease-out
transition: transform 180ms ease-out;
}
.animate-25-50-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
transition: transform 180ms ease-out
transition: transform 180ms ease-out;
}
.animate-50-75-a {
-webkit-transform: rotate(270deg);
transform: rotate(270deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
transition: transform 180ms ease-out
}
.animate-50-75-b,
.animate-75-100-a {
-webkit-transition: -webkit-transform 180ms ease-out;
-o-transition: transform 180ms ease-out
transition: transform 180ms ease-out;
}
.animate-50-75-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
transition: transform 180ms ease-out
transition: transform 180ms ease-out;
}
.animate-75-100-a {
-webkit-transform: rotate(0);
transform: rotate(0);
-webkit-transform-origin: 100% 100%;
transform: rotate(0deg);
transform-origin: 100% 100%;
transition: transform 180ms ease-out
transition: transform 180ms ease-out;
}
.animate-75-100-b {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
-webkit-transition: -webkit-transform 180ms ease-out;
-o-transition: transform 180ms ease-out;
transition: transform 180ms ease-out
}
transition: transform 180ms ease-out;
}
@@ -1,21 +1,105 @@
define(["require", "css!./emby-progressring", "registerElement"], function(require) {
"use strict";
define(['require', 'css!./emby-progressring', 'registerElement'], function (require) {
'use strict';
var EmbyProgressRing = Object.create(HTMLDivElement.prototype);
return EmbyProgressRing.createdCallback = function() {
this.classList.add("progressring");
EmbyProgressRing.createdCallback = function () {
this.classList.add('progressring');
var instance = this;
require(["text!./emby-progressring.template.html"], function(template) {
instance.innerHTML = template, instance.setProgress(parseFloat(instance.getAttribute("data-progress") || "0"))
})
}, EmbyProgressRing.setProgress = function(progress) {
require(['text!./emby-progressring.template.html'], function (template) {
instance.innerHTML = template;
//if (window.MutationObserver) {
// // create an observer instance
// var observer = new MutationObserver(function (mutations) {
// mutations.forEach(function (mutation) {
// instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
// });
// });
// // configuration of the observer:
// var config = { attributes: true, childList: false, characterData: false };
// // pass in the target node, as well as the observer options
// observer.observe(instance, config);
// instance.observer = observer;
//}
instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
});
};
EmbyProgressRing.setProgress = function (progress) {
progress = Math.floor(progress);
var angle;
progress < 25 ? (angle = progress / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-25-50-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-50-75-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 25 && progress < 50 ? (angle = (progress - 25) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-50-75-b").style.transform = "rotate(-90deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 50 && progress < 75 ? (angle = (progress - 50) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "none", this.querySelector(".animate-50-75-b").style.transform = "rotate(" + angle + "deg)", this.querySelector(".animate-75-100-b").style.transform = "rotate(-90deg)") : progress >= 75 && progress <= 100 && (angle = (progress - 75) / 100 * 360 - 90, this.querySelector(".animate-0-25-b").style.transform = "none", this.querySelector(".animate-25-50-b").style.transform = "none", this.querySelector(".animate-50-75-b").style.transform = "none", this.querySelector(".animate-75-100-b").style.transform = "rotate(" + angle + "deg)"), this.querySelector(".progressring-text").innerHTML = progress + "%"
}, EmbyProgressRing.attachedCallback = function() {}, EmbyProgressRing.detachedCallback = function() {
if (progress < 25) {
angle = -90 + (progress / 100) * 360;
this.querySelector('.animate-0-25-b').style.transform = 'rotate(' + angle + 'deg)';
this.querySelector('.animate-25-50-b').style.transform = 'rotate(-90deg)';
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
}
else if (progress >= 25 && progress < 50) {
angle = -90 + ((progress - 25) / 100) * 360;
this.querySelector('.animate-0-25-b').style.transform = 'none';
this.querySelector('.animate-25-50-b').style.transform = 'rotate(' + angle + 'deg)';
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
}
else if (progress >= 50 && progress < 75) {
angle = -90 + ((progress - 50) / 100) * 360;
this.querySelector('.animate-0-25-b').style.transform = 'none';
this.querySelector('.animate-25-50-b').style.transform = 'none';
this.querySelector('.animate-50-75-b').style.transform = 'rotate(' + angle + 'deg)';
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
}
else if (progress >= 75 && progress <= 100) {
angle = -90 + ((progress - 75) / 100) * 360;
this.querySelector('.animate-0-25-b').style.transform = 'none';
this.querySelector('.animate-25-50-b').style.transform = 'none';
this.querySelector('.animate-50-75-b').style.transform = 'none';
this.querySelector('.animate-75-100-b').style.transform = 'rotate(' + angle + 'deg)';
}
this.querySelector('.progressring-text').innerHTML = progress + '%';
};
EmbyProgressRing.attachedCallback = function () {
};
EmbyProgressRing.detachedCallback = function () {
var observer = this.observer;
observer && (observer.disconnect(), this.observer = null)
}, document.registerElement("emby-progressring", {
if (observer) {
// later, you can stop observing
observer.disconnect();
this.observer = null;
}
};
document.registerElement('emby-progressring', {
prototype: EmbyProgressRing,
extends: "div"
}), EmbyProgressRing
extends: 'div'
});
return EmbyProgressRing;
});
@@ -2,26 +2,26 @@
position: relative;
line-height: 24px;
display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding-left: 24px
padding-left: 0;
}
.radio-label-block {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
margin-top: .5em;
margin-bottom: .5em
margin-bottom: .5em;
}
.mdl-radio {
padding-left: 24px;
}
.mdl-radio__button {
line-height: 24px;
position: absolute;
/* 1px is for focusing purposes, so the focusManager doesn't skip over it */
width: 1px;
height: 1px;
margin: 0;
@@ -31,7 +31,7 @@
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
border: none
border: none;
}
.mdl-radio__outer-circle {
@@ -39,25 +39,23 @@
top: 4px;
left: 0;
display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 16px;
height: 16px;
margin: 0;
cursor: pointer;
border: 2px solid currentcolor;
-webkit-border-radius: 50%;
border-radius: 50%;
z-index: 2
z-index: 2;
}
.mdl-radio__button:checked+.mdl-radio__label+.mdl-radio__outer-circle {
border: 2px solid #00a4dc
.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle {
border: 2px solid #00a4dc;
}
.mdl-radio__button:disabled+.mdl-radio__label+.mdl-radio__outer-circle {
border: 2px solid rgba(0, 0, 0, .26);
cursor: auto
.mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle {
border: 2px solid rgba(0,0,0, 0.26);
cursor: auto;
}
.mdl-radio__inner-circle {
@@ -66,52 +64,44 @@
margin: 0;
top: 8px;
left: 4px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 8px;
height: 8px;
cursor: pointer;
-webkit-transition-duration: .28s;
-o-transition-duration: .28s;
transition-duration: .28s;
-webkit-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
-o-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
-o-transition-property: transform;
-webkit-transition-property: -webkit-transform, -webkit-transform;
transition-duration: 0.28s;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-property: -webkit-transform;
transition-property: transform;
transition-property: transform, -webkit-transform;
-webkit-transform: scale3d(0, 0, 0);
transform: scale3d(0, 0, 0);
-webkit-border-radius: 50%;
border-radius: 50%;
background: #00a4dc
background: #00a4dc;
}
.mdl-radio__button:checked+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1)
transform: scale3d(1, 1, 1);
}
.mdl-radio__button:disabled+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
background: rgba(0, 0, 0, .26);
cursor: auto
.mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
background: rgba(0,0,0, 0.26);
cursor: auto;
}
.mdl-radio__button:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
-webkit-box-shadow: 0 0 0 10px rgba(255, 255, 255, .76);
box-shadow: 0 0 0 10px rgba(255, 255, 255, .76)
.mdl-radio__button:focus + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
box-shadow: 0 0 0px 10px rgba(255, 255, 255, 0.76);
}
.mdl-radio__button:checked:focus+.mdl-radio__label+.mdl-radio__outer-circle+.mdl-radio__inner-circle {
-webkit-box-shadow: 0 0 0 10px rgba(0,164,220, .26);
box-shadow: 0 0 0 10px rgba(0,164,220, .26)
.mdl-radio__button:checked:focus + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle {
box-shadow: 0 0 0 10px rgba(0, 164, 220, 0.26)
}
.mdl-radio__label {
cursor: pointer
cursor: pointer;
}
.mdl-radio__button:disabled+.mdl-radio__label {
color: rgba(0, 0, 0, .26);
cursor: auto
}
.mdl-radio__button:disabled + .mdl-radio__label {
color: rgba(0,0,0, 0.26);
cursor: auto;
}
@@ -1,20 +1,48 @@
define(["css!./emby-radio", "registerElement"], function() {
"use strict";
define(['css!./emby-radio', 'registerElement'], function () {
'use strict';
var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) {
if (13 === e.keyCode) return e.preventDefault(), this.checked = !0, !1
}
var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
EmbyRadioPrototype.attachedCallback = function() {
if ("true" !== this.getAttribute("data-radio")) {
this.setAttribute("data-radio", "true"), this.classList.add("mdl-radio__button");
var labelElement = this.parentNode;
labelElement.classList.add("mdl-radio"), labelElement.classList.add("mdl-js-radio"), labelElement.classList.add("mdl-js-ripple-effect");
var labelTextElement = labelElement.querySelector("span");
labelTextElement.classList.add("radioButtonLabel"), labelTextElement.classList.add("mdl-radio__label"), labelElement.insertAdjacentHTML("beforeend", '<span class="mdl-radio__outer-circle"></span><span class="mdl-radio__inner-circle"></span>'), this.addEventListener("keydown", onKeyDown)
// Don't submit form on enter
if (e.keyCode === 13) {
e.preventDefault();
this.checked = true;
return false;
}
}, document.registerElement("emby-radio", {
}
EmbyRadioPrototype.attachedCallback = function () {
if (this.getAttribute('data-radio') === 'true') {
return;
}
this.setAttribute('data-radio', 'true');
this.classList.add('mdl-radio__button');
var labelElement = this.parentNode;
//labelElement.classList.add('"mdl-radio mdl-js-radio mdl-js-ripple-effect');
labelElement.classList.add('mdl-radio');
labelElement.classList.add('mdl-js-radio');
labelElement.classList.add('mdl-js-ripple-effect');
var labelTextElement = labelElement.querySelector('span');
labelTextElement.classList.add('radioButtonLabel');
labelTextElement.classList.add('mdl-radio__label');
labelElement.insertAdjacentHTML('beforeend', '<span class="mdl-radio__outer-circle"></span><span class="mdl-radio__inner-circle"></span>');
this.addEventListener('keydown', onKeyDown);
};
document.registerElement('emby-radio', {
prototype: EmbyRadioPrototype,
extends: "input"
})
extends: 'input'
});
});
@@ -1,67 +1,60 @@
.emby-scrollbuttons-scroller {
position: relative
position: relative;
}
.scrollbuttoncontainer {
position: absolute;
top: 0;
bottom: 0;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
z-index: 1;
font-size: 3em;
color: #fff;
display: none;
overflow: hidden
overflow: hidden;
}
.scrollbuttoncontainer-left {
background: rgba(20, 20, 20, .5);
background: -webkit-linear-gradient(left, #000 0, rgba(0, 0, 0, 0) 100%);
background: -webkit-gradient(linear, left top, right top, from(#000), to(rgba(0, 0, 0, 0)));
background: -webkit-linear-gradient(left, #000, rgba(0, 0, 0, 0));
background: -o-linear-gradient(left, #000, rgba(0, 0, 0, 0));
background: linear-gradient(to right, #000, rgba(0, 0, 0, 0));
left: 0
background: -moz-linear-gradient(left,#000 0,rgba(0,0,0,0) 100%);
background: -webkit-linear-gradient(left,#000 0,rgba(0,0,0,0) 100%);
background: linear-gradient(to right,#000,rgba(0,0,0,0));
}
.scrollbuttoncontainer-right {
background: rgba(20, 20, 20, .5);
background: -webkit-linear-gradient(right, #000 0, rgba(0, 0, 0, 0) 100%);
background: -webkit-gradient(linear, right top, left top, from(#000), to(rgba(0, 0, 0, 0)));
background: -webkit-linear-gradient(right, #000, rgba(0, 0, 0, 0));
background: -o-linear-gradient(right, #000, rgba(0, 0, 0, 0));
background: linear-gradient(to left, #000, rgba(0, 0, 0, 0));
right: 0
background: -moz-linear-gradient(right,#000 0,rgba(0,0,0,0) 100%);
background: -webkit-linear-gradient(right,#000 0,rgba(0,0,0,0) 100%);
background: linear-gradient(to left,#000,rgba(0,0,0,0));
}
.emby-scrollbuttons-scroller:hover .scrollbuttoncontainer {
display: -webkit-box;
display: -webkit-flex;
display: flex
display: flex;
}
.scrollbuttoncontainer-left {
left: 0;
}
.scrollbuttoncontainer-right {
right: 0;
}
.emby-scrollbuttons-scrollbutton {
margin: 0 -.2em;
-webkit-transition: -webkit-transform 160ms ease-out;
-o-transition: transform 160ms ease-out;
transition: transform 160ms ease-out
transition: transform 160ms ease-out;
}
.scrollbuttoncontainer:hover>.emby-scrollbuttons-scrollbutton {
-webkit-transform: scale(1.3, 1.3);
transform: scale(1.3, 1.3)
.scrollbuttoncontainer:hover > .emby-scrollbuttons-scrollbutton {
transform: scale(1.3, 1.3);
}
.emby-scrollbuttons-scrollbutton:after {
content: '';
display: none !important
display: none !important;
}
.emby-scrollbuttons-scrollbutton:focus {
color: inherit !important
}
color: inherit !important;
}
@@ -1,75 +1,201 @@
define(["layoutManager", "dom", "css!./emby-scrollbuttons", "registerElement", "paper-icon-button-light"], function(layoutManager, dom) {
"use strict";
define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'registerElement', 'paper-icon-button-light'], function (layoutManager, dom) {
'use strict';
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
EmbyScrollButtonsPrototype.createdCallback = function () {
};
function getScrollButtonContainerHtml(direction) {
var html = "";
html += '<div class="scrollbuttoncontainer scrollbuttoncontainer-' + direction + ("left" === direction ? " hide" : "") + '">';
var icon = "left" === direction ? "&#xE5CB;" : "&#xE5CC;";
return html += '<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="' + direction + '" class="emby-scrollbuttons-scrollbutton">', html += '<i class="md-icon">' + icon + "</i>", html += "</button>", html += "</div>"
var html = '';
var hide = direction === 'left' ? ' hide' : '';
html += '<div class="scrollbuttoncontainer scrollbuttoncontainer-' + direction + hide + '">';
var icon = direction === 'left' ? '&#xE5CB;' : '&#xE5CC;';
html += '<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="' + direction + '" class="emby-scrollbuttons-scrollbutton">';
html += '<i class="md-icon">' + icon + '</i>';
html += '</button>';
html += '</div>';
return html;
}
function getScrollPosition(parent) {
return parent.getScrollPosition ? parent.getScrollPosition() : 0
if (parent.getScrollPosition) {
return parent.getScrollPosition();
}
return 0;
}
function getScrollWidth(parent) {
return parent.getScrollSize ? parent.getScrollSize() : 0
if (parent.getScrollSize) {
return parent.getScrollSize();
}
return 0;
}
function onScrolledToPosition(scrollButtons, pos, scrollWidth) {
pos > 0 ? scrollButtons.scrollButtonsLeft.classList.remove("hide") : scrollButtons.scrollButtonsLeft.classList.add("hide"), scrollWidth > 0 && (pos += scrollButtons.offsetWidth, pos >= scrollWidth ? scrollButtons.scrollButtonsRight.classList.add("hide") : scrollButtons.scrollButtonsRight.classList.remove("hide"))
if (pos > 0) {
scrollButtons.scrollButtonsLeft.classList.remove('hide');
} else {
scrollButtons.scrollButtonsLeft.classList.add('hide');
}
if (scrollWidth > 0) {
pos += scrollButtons.offsetWidth;
if (pos >= scrollWidth) {
scrollButtons.scrollButtonsRight.classList.add('hide');
} else {
scrollButtons.scrollButtonsRight.classList.remove('hide');
}
}
}
function onScroll(e) {
var scrollButtons = this,
scroller = this.scroller;
onScrolledToPosition(scrollButtons, getScrollPosition(scroller), getScrollWidth(scroller))
var scrollButtons = this;
var scroller = this.scroller;
var pos = getScrollPosition(scroller);
var scrollWidth = getScrollWidth(scroller);
onScrolledToPosition(scrollButtons, pos, scrollWidth);
}
function getStyleValue(style, name) {
var value = style.getPropertyValue(name);
return value && (value = value.replace("px", "")) ? (value = parseInt(value), isNaN(value) ? 0 : value) : 0
if (!value) {
return 0;
}
value = value.replace('px', '');
if (!value) {
return 0;
}
value = parseInt(value);
if (isNaN(value)) {
return 0;
}
return value;
}
function getScrollSize(elem) {
var scrollSize = elem.offsetWidth,
style = window.getComputedStyle(elem, null),
paddingLeft = getStyleValue(style, "padding-left");
paddingLeft && (scrollSize -= paddingLeft);
var paddingRight = getStyleValue(style, "padding-right");
paddingRight && (scrollSize -= paddingRight);
var scrollSize = elem.offsetWidth;
var style = window.getComputedStyle(elem, null);
var paddingLeft = getStyleValue(style, 'padding-left');
if (paddingLeft) {
scrollSize -= paddingLeft;
}
var paddingRight = getStyleValue(style, 'padding-right');
if (paddingRight) {
scrollSize -= paddingRight;
}
var slider = elem.getScrollSlider();
return style = window.getComputedStyle(slider, null), paddingLeft = getStyleValue(style, "padding-left"), paddingLeft && (scrollSize -= paddingLeft), paddingRight = getStyleValue(style, "padding-right"), paddingRight && (scrollSize -= paddingRight), scrollSize
style = window.getComputedStyle(slider, null);
paddingLeft = getStyleValue(style, 'padding-left');
if (paddingLeft) {
scrollSize -= paddingLeft;
}
paddingRight = getStyleValue(style, 'padding-right');
if (paddingRight) {
scrollSize -= paddingRight;
}
return scrollSize;
}
function onScrollButtonClick(e) {
var newPos, parent = dom.parentWithAttribute(this, "is", "emby-scroller"),
direction = this.getAttribute("data-direction"),
scrollSize = getScrollSize(parent),
pos = getScrollPosition(parent);
newPos = "left" === direction ? Math.max(0, pos - scrollSize) : pos + scrollSize, parent.scrollToPosition(newPos, !1)
var parent = dom.parentWithAttribute(this, 'is', 'emby-scroller');
var direction = this.getAttribute('data-direction');
var scrollSize = getScrollSize(parent);
var pos = getScrollPosition(parent);
var newPos;
if (direction === 'left') {
newPos = Math.max(0, pos - scrollSize);
} else {
newPos = pos + scrollSize;
}
parent.scrollToPosition(newPos, false);
}
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
EmbyScrollButtonsPrototype.createdCallback = function() {}, EmbyScrollButtonsPrototype.attachedCallback = function() {
var parent = dom.parentWithAttribute(this, "is", "emby-scroller");
this.scroller = parent, parent.classList.add("emby-scrollbuttons-scroller"), this.innerHTML = getScrollButtonContainerHtml("left") + getScrollButtonContainerHtml("right");
EmbyScrollButtonsPrototype.attachedCallback = function () {
var parent = dom.parentWithAttribute(this, 'is', 'emby-scroller');
this.scroller = parent;
parent.classList.add('emby-scrollbuttons-scroller');
this.innerHTML = getScrollButtonContainerHtml('left') + getScrollButtonContainerHtml('right');
var scrollHandler = onScroll.bind(this);
this.scrollHandler = scrollHandler;
var buttons = this.querySelectorAll(".emby-scrollbuttons-scrollbutton");
buttons[0].addEventListener("click", onScrollButtonClick), buttons[1].addEventListener("click", onScrollButtonClick), buttons = this.querySelectorAll(".scrollbuttoncontainer"), this.scrollButtonsLeft = buttons[0], this.scrollButtonsRight = buttons[1], parent.addScrollEventListener(scrollHandler, {
capture: !1,
passive: !0
})
}, EmbyScrollButtonsPrototype.detachedCallback = function() {
var buttons = this.querySelectorAll('.emby-scrollbuttons-scrollbutton');
buttons[0].addEventListener('click', onScrollButtonClick);
buttons[1].addEventListener('click', onScrollButtonClick);
buttons = this.querySelectorAll('.scrollbuttoncontainer');
this.scrollButtonsLeft = buttons[0];
this.scrollButtonsRight = buttons[1];
parent.addScrollEventListener(scrollHandler, {
capture: false,
passive: true
});
};
EmbyScrollButtonsPrototype.detachedCallback = function () {
var parent = this.scroller;
this.scroller = null;
var scrollHandler = this.scrollHandler;
parent && scrollHandler && parent.removeScrollEventListener(scrollHandler, {
capture: !1,
passive: !0
}), this.scrollHandler = null, this.scrollButtonsLeft = null, this.scrollButtonsRight = null
}, document.registerElement("emby-scrollbuttons", {
if (parent && scrollHandler) {
parent.removeScrollEventListener(scrollHandler, {
capture: false,
passive: true
});
}
this.scrollHandler = null;
this.scrollButtonsLeft = null;
this.scrollButtonsRight = null;
};
document.registerElement('emby-scrollbuttons', {
prototype: EmbyScrollButtonsPrototype,
extends: "div"
})
extends: 'div'
});
});
@@ -1,101 +1,224 @@
define(["scroller", "dom", "layoutManager", "inputManager", "focusManager", "browser", "registerElement"], function(scroller, dom, layoutManager, inputManager, focusManager, browser) {
"use strict";
define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'browser', 'registerElement'], function (scroller, dom, layoutManager, inputManager, focusManager, browser) {
'use strict';
var ScrollerProtoType = Object.create(HTMLDivElement.prototype);
ScrollerProtoType.createdCallback = function () {
this.classList.add('emby-scroller');
};
function initCenterFocus(elem, scrollerInstance) {
dom.addEventListener(elem, "focus", function(e) {
dom.addEventListener(elem, 'focus', function (e) {
var focused = focusManager.focusableParent(e.target);
focused && scrollerInstance.toCenter(focused)
if (focused) {
scrollerInstance.toCenter(focused);
}
}, {
capture: !0,
passive: !0
})
capture: true,
passive: true
});
}
ScrollerProtoType.scrollToBeginning = function () {
if (this.scroller) {
this.scroller.slideTo(0, true);
}
};
ScrollerProtoType.toStart = function (elem, immediate) {
if (this.scroller) {
this.scroller.toStart(elem, immediate);
}
};
ScrollerProtoType.toCenter = function (elem, immediate) {
if (this.scroller) {
this.scroller.toCenter(elem, immediate);
}
};
ScrollerProtoType.scrollToPosition = function (pos, immediate) {
if (this.scroller) {
this.scroller.slideTo(pos, immediate);
}
};
ScrollerProtoType.getScrollPosition = function () {
if (this.scroller) {
return this.scroller.getScrollPosition();
}
};
ScrollerProtoType.getScrollSize = function () {
if (this.scroller) {
return this.scroller.getScrollSize();
}
};
ScrollerProtoType.getScrollEventName = function () {
if (this.scroller) {
return this.scroller.getScrollEventName();
}
};
ScrollerProtoType.getScrollSlider = function () {
if (this.scroller) {
return this.scroller.getScrollSlider();
}
};
ScrollerProtoType.addScrollEventListener = function (fn, options) {
if (this.scroller) {
dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
}
};
ScrollerProtoType.removeScrollEventListener = function (fn, options) {
if (this.scroller) {
dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
}
};
function onInputCommand(e) {
var cmd = e.detail.command;
"end" === cmd ? (focusManager.focusLast(this, "." + this.getAttribute("data-navcommands")), e.preventDefault(), e.stopPropagation()) : "pageup" === cmd ? (focusManager.moveFocus(e.target, this, "." + this.getAttribute("data-navcommands"), -12), e.preventDefault(), e.stopPropagation()) : "pagedown" === cmd && (focusManager.moveFocus(e.target, this, "." + this.getAttribute("data-navcommands"), 12), e.preventDefault(), e.stopPropagation())
if (cmd === 'end') {
focusManager.focusLast(this, '.' + this.getAttribute('data-navcommands'));
e.preventDefault();
e.stopPropagation();
}
else if (cmd === 'pageup') {
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), -12);
e.preventDefault();
e.stopPropagation();
}
else if (cmd === 'pagedown') {
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), 12);
e.preventDefault();
e.stopPropagation();
}
}
function initHeadroom(elem) {
require(["headroom"], function(Headroom) {
require(['headroom'], function (Headroom) {
var headroom = new Headroom([], {
scroller: elem
});
headroom.init(), headroom.add(document.querySelector(".skinHeader")), elem.headroom = headroom
})
// initialise
headroom.init();
headroom.add(document.querySelector('.skinHeader'));
elem.headroom = headroom;
});
}
ScrollerProtoType.attachedCallback = function () {
if (this.getAttribute('data-navcommands')) {
inputManager.on(this, onInputCommand);
}
var horizontal = this.getAttribute('data-horizontal') !== 'false';
var slider = this.querySelector('.scrollSlider');
if (horizontal) {
slider.style['white-space'] = 'nowrap';
}
var bindHeader = this.getAttribute('data-bindheader') === 'true';
var scrollFrame = this;
var enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false';
var options = {
horizontal: horizontal,
mouseDragging: 1,
mouseWheel: this.getAttribute('data-mousewheel') !== 'false',
touchDragging: 1,
slidee: slider,
scrollBy: 200,
speed: horizontal ? 270 : 240,
//immediateSpeed: pageOptions.immediateSpeed,
elasticBounds: 1,
dragHandle: 1,
scrollWidth: this.getAttribute('data-scrollsize') === 'auto' ? null : 5000000,
autoImmediate: true,
skipSlideToWhenVisible: this.getAttribute('data-skipfocuswhenvisible') === 'true',
dispatchScrollEvent: enableScrollButtons || bindHeader || this.getAttribute('data-scrollevent') === 'true',
hideScrollbar: enableScrollButtons || this.getAttribute('data-hidescrollbar') === 'true',
allowNativeSmoothScroll: this.getAttribute('data-allownativesmoothscroll') === 'true' && !enableScrollButtons,
allowNativeScroll: !enableScrollButtons,
forceHideScrollbars: enableScrollButtons,
// In edge, with the native scroll, the content jumps around when hovering over the buttons
requireAnimation: enableScrollButtons && browser.edge
};
// If just inserted it might not have any height yet - yes this is a hack
this.scroller = new scroller(scrollFrame, options);
this.scroller.init();
if (layoutManager.tv && this.getAttribute('data-centerfocus')) {
initCenterFocus(this, this.scroller);
}
if (bindHeader) {
initHeadroom(this);
}
if (enableScrollButtons) {
loadScrollButtons(this);
}
};
function loadScrollButtons(scroller) {
require(["emby-scrollbuttons"], function() {
scroller.insertAdjacentHTML("beforeend", '<div is="emby-scrollbuttons"></div>')
})
require(['emby-scrollbuttons'], function () {
scroller.insertAdjacentHTML('beforeend', '<div is="emby-scrollbuttons"></div>');
});
}
var ScrollerProtoType = Object.create(HTMLDivElement.prototype);
ScrollerProtoType.createdCallback = function() {
this.classList.add("emby-scroller")
}, ScrollerProtoType.scrollToBeginning = function() {
this.scroller && this.scroller.slideTo(0, !0)
}, ScrollerProtoType.toStart = function(elem, immediate) {
this.scroller && this.scroller.toStart(elem, immediate)
}, ScrollerProtoType.toCenter = function(elem, immediate) {
this.scroller && this.scroller.toCenter(elem, immediate)
}, ScrollerProtoType.scrollToPosition = function(pos, immediate) {
this.scroller && this.scroller.slideTo(pos, immediate)
}, ScrollerProtoType.getScrollPosition = function() {
if (this.scroller) return this.scroller.getScrollPosition()
}, ScrollerProtoType.getScrollSize = function() {
if (this.scroller) return this.scroller.getScrollSize()
}, ScrollerProtoType.getScrollEventName = function() {
if (this.scroller) return this.scroller.getScrollEventName()
}, ScrollerProtoType.getScrollSlider = function() {
if (this.scroller) return this.scroller.getScrollSlider()
}, ScrollerProtoType.addScrollEventListener = function(fn, options) {
this.scroller && dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options)
}, ScrollerProtoType.removeScrollEventListener = function(fn, options) {
this.scroller && dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options)
}, ScrollerProtoType.attachedCallback = function() {
this.getAttribute("data-navcommands") && inputManager.on(this, onInputCommand);
var horizontal = "false" !== this.getAttribute("data-horizontal"),
slider = this.querySelector(".scrollSlider");
horizontal && (slider.style["white-space"] = "nowrap");
var bindHeader = "true" === this.getAttribute("data-bindheader"),
scrollFrame = this,
enableScrollButtons = layoutManager.desktop && horizontal && "false" !== this.getAttribute("data-scrollbuttons"),
options = {
horizontal: horizontal,
mouseDragging: 1,
mouseWheel: "false" !== this.getAttribute("data-mousewheel"),
touchDragging: 1,
slidee: slider,
scrollBy: 200,
speed: horizontal ? 270 : 240,
elasticBounds: 1,
dragHandle: 1,
scrollWidth: "auto" === this.getAttribute("data-scrollsize") ? null : 5e6,
autoImmediate: !0,
skipSlideToWhenVisible: "true" === this.getAttribute("data-skipfocuswhenvisible"),
dispatchScrollEvent: enableScrollButtons || bindHeader || "true" === this.getAttribute("data-scrollevent"),
hideScrollbar: enableScrollButtons || "true" === this.getAttribute("data-hidescrollbar"),
allowNativeSmoothScroll: "true" === this.getAttribute("data-allownativesmoothscroll") && !enableScrollButtons,
allowNativeScroll: !enableScrollButtons,
forceHideScrollbars: enableScrollButtons,
requireAnimation: enableScrollButtons && browser.edge
};
this.scroller = new scroller(scrollFrame, options), this.scroller.init(), layoutManager.tv && this.getAttribute("data-centerfocus") && initCenterFocus(this, this.scroller), bindHeader && initHeadroom(this), enableScrollButtons && loadScrollButtons(this)
}, ScrollerProtoType.pause = function() {
ScrollerProtoType.pause = function () {
var headroom = this.headroom;
headroom && headroom.pause()
}, ScrollerProtoType.resume = function() {
if (headroom) {
headroom.pause();
}
};
ScrollerProtoType.resume = function () {
var headroom = this.headroom;
headroom && headroom.resume()
}, ScrollerProtoType.detachedCallback = function() {
this.getAttribute("data-navcommands") && inputManager.off(this, onInputCommand);
if (headroom) {
headroom.resume();
}
};
ScrollerProtoType.detachedCallback = function () {
if (this.getAttribute('data-navcommands')) {
inputManager.off(this, onInputCommand);
}
var headroom = this.headroom;
headroom && (headroom.destroy(), this.headroom = null);
if (headroom) {
headroom.destroy();
this.headroom = null;
}
var scrollerInstance = this.scroller;
scrollerInstance && (scrollerInstance.destroy(), this.scroller = null)
}, document.registerElement("emby-scroller", {
if (scrollerInstance) {
scrollerInstance.destroy();
this.scroller = null;
}
};
document.registerElement('emby-scroller', {
prototype: ScrollerProtoType,
extends: "div"
})
extends: 'div'
});
});
@@ -2,91 +2,84 @@
display: block;
margin: 0;
margin-bottom: 0 !important;
/* Remove select styling */
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
font-size: 110%;
/* General select styles: change as needed */
font-family: inherit;
font-weight: inherit;
padding: .5em 1.9em .5em .5em;
-webkit-box-sizing: border-box;
/* Prevent padding from causing width overflow */
box-sizing: border-box;
outline: 0 !important;
-webkit-tap-highlight-color: transparent;
width: 100%
outline: none !important;
-webkit-tap-highlight-color: rgba(0,0,0,0);
width: 100%;
}
.emby-select[disabled] {
background: 0 0 !important;
border-color: transparent !important;
color: inherit !important;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none
}
.emby-select[disabled] {
background: none !important;
border-color: transparent !important;
color: inherit !important;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.selectContainer-inline>.emby-select {
.selectContainer-inline > .emby-select {
padding: .3em 1.9em .3em .5em;
font-size: inherit
font-size: inherit;
}
.selectContainer-inline>.emby-select[disabled] {
padding-left: 0;
padding-right: 0
}
.selectContainer-inline > .emby-select[disabled] {
padding-left: 0;
padding-right: 0;
}
.emby-select::-moz-focus-inner {
border: 0
border: 0;
}
.emby-select-focusscale {
-webkit-transition: -webkit-transform 180ms ease-out !important;
-o-transition: transform 180ms ease-out !important;
transition: transform 180ms ease-out !important;
-webkit-transform-origin: center center;
transform-origin: center center
transform-origin: center center;
}
.emby-select-focusscale:focus {
-webkit-transform: scale(1.04);
transform: scale(1.04);
z-index: 1
}
.emby-select-focusscale:focus {
transform: scale(1.04);
z-index: 1;
}
.emby-select+.fieldDescription {
margin-top: .25em
.emby-select + .fieldDescription {
margin-top: .25em;
}
.selectContainer {
margin-bottom: 1.8em;
position: relative
position: relative;
}
.selectContainer-inline {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
margin-bottom: 0;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center
align-items: center;
}
.selectLabel {
display: block;
margin-bottom: .25em
margin-bottom: .25em;
}
.selectContainer-inline>.selectLabel {
.selectContainer-inline > .selectLabel {
margin-bottom: 0;
margin-right: .5em;
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.emby-select-withcolor {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
-webkit-border-radius: .2em;
border-radius: .2em
border-radius: .2em;
}
.selectArrowContainer {
@@ -94,25 +87,24 @@
right: .3em;
top: .2em;
color: inherit;
pointer-events: none
pointer-events: none;
}
.selectContainer-inline>.selectArrowContainer {
.selectContainer-inline > .selectArrowContainer {
top: initial;
bottom: .24em;
font-size: 90%
font-size: 90%;
}
.emby-select[disabled]+.selectArrowContainer {
display: none
.emby-select[disabled] + .selectArrowContainer {
display: none;
}
.selectArrow {
margin-top: .35em;
font-size: 1.7em
font-size: 1.7em;
}
.emby-select-iconbutton {
-webkit-align-self: flex-end;
align-self: flex-end
}
align-self: flex-end;
}
@@ -1,75 +1,168 @@
define(["layoutManager", "browser", "actionsheet", "css!./emby-select", "registerElement"], function(layoutManager, browser, actionsheet) {
"use strict";
define(['layoutManager', 'browser', 'actionsheet', 'css!./emby-select', 'registerElement'], function (layoutManager, browser, actionsheet) {
'use strict';
var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype);
function enableNativeMenu() {
return !(!browser.edgeUwp && !browser.xboxOne) || !(browser.tizen || browser.orsay || browser.web0s) && (!!browser.tv || !layoutManager.tv)
if (browser.edgeUwp || browser.xboxOne) {
return true;
}
// Doesn't seem to work at all
if (browser.tizen || browser.orsay || browser.web0s) {
return false;
}
// Take advantage of the native input methods
if (browser.tv) {
return true;
}
if (layoutManager.tv) {
return false;
}
return true;
}
function triggerChange(select) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", !1, !0), select.dispatchEvent(evt)
evt.initEvent("change", false, true);
select.dispatchEvent(evt);
}
function setValue(select, value) {
select.value = value
select.value = value;
}
function showActionSheet(select) {
var labelElem = getLabel(select),
title = labelElem ? labelElem.textContent || labelElem.innerText : null;
var labelElem = getLabel(select);
var title = labelElem ? (labelElem.textContent || labelElem.innerText) : null;
actionsheet.show({
items: select.options,
positionTo: select,
title: title
}).then(function(value) {
setValue(select, value), triggerChange(select)
})
}).then(function (value) {
setValue(select, value);
triggerChange(select);
});
}
function getLabel(select) {
for (var elem = select.previousSibling; elem && "LABEL" !== elem.tagName;) elem = elem.previousSibling;
return elem
var elem = select.previousSibling;
while (elem && elem.tagName !== 'LABEL') {
elem = elem.previousSibling;
}
return elem;
}
function onFocus(e) {
var label = getLabel(this);
label && label.classList.add("selectLabelFocused")
if (label) {
label.classList.add('selectLabelFocused');
}
}
function onBlur(e) {
var label = getLabel(this);
label && label.classList.remove("selectLabelFocused")
if (label) {
label.classList.remove('selectLabelFocused');
}
}
function onMouseDown(e) {
e.button || enableNativeMenu() || (e.preventDefault(), showActionSheet(this))
// e.button=0 for primary (left) mouse button click
if (!e.button && !enableNativeMenu()) {
e.preventDefault();
showActionSheet(this);
}
}
function onKeyDown(e) {
switch (e.keyCode) {
case 13:
return void(enableNativeMenu() || (e.preventDefault(), showActionSheet(this)));
if (!enableNativeMenu()) {
e.preventDefault();
showActionSheet(this);
}
return;
case 37:
case 38:
case 39:
case 40:
return void(layoutManager.tv && e.preventDefault())
if (layoutManager.tv) {
e.preventDefault();
}
return;
default:
break;
}
}
var EmbySelectPrototype = Object.create(HTMLSelectElement.prototype),
inputId = 0;
EmbySelectPrototype.createdCallback = function() {
this.id || (this.id = "embyselect" + inputId, inputId++), browser.firefox || (this.classList.add("emby-select-withcolor"), layoutManager.tv && this.classList.add("emby-select-tv-withcolor")), layoutManager.tv && this.classList.add("emby-select-focusscale"), this.addEventListener("mousedown", onMouseDown), this.addEventListener("keydown", onKeyDown), this.addEventListener("focus", onFocus), this.addEventListener("blur", onBlur)
}, EmbySelectPrototype.attachedCallback = function() {
if (!this.classList.contains("emby-select")) {
this.classList.add("emby-select");
var label = this.ownerDocument.createElement("label");
label.innerHTML = this.getAttribute("label") || "", label.classList.add("selectLabel"), label.htmlFor = this.id, this.parentNode.insertBefore(label, this), this.classList.contains("emby-select-withcolor") && this.parentNode.insertAdjacentHTML("beforeend", '<div class="selectArrowContainer"><div style="visibility:hidden;">0</div><i class="selectArrow md-icon">&#xE313;</i></div>')
var inputId = 0;
EmbySelectPrototype.createdCallback = function () {
if (!this.id) {
this.id = 'embyselect' + inputId;
inputId++;
}
}, EmbySelectPrototype.setLabel = function(text) {
this.parentNode.querySelector("label").innerHTML = text
}, document.registerElement("emby-select", {
if (!browser.firefox) {
this.classList.add('emby-select-withcolor');
if (layoutManager.tv) {
this.classList.add('emby-select-tv-withcolor');
}
}
if (layoutManager.tv) {
this.classList.add('emby-select-focusscale');
}
this.addEventListener('mousedown', onMouseDown);
this.addEventListener('keydown', onKeyDown);
this.addEventListener('focus', onFocus);
this.addEventListener('blur', onBlur);
};
EmbySelectPrototype.attachedCallback = function () {
if (this.classList.contains('emby-select')) {
return;
}
this.classList.add('emby-select');
var label = this.ownerDocument.createElement('label');
label.innerHTML = this.getAttribute('label') || '';
label.classList.add('selectLabel');
label.htmlFor = this.id;
this.parentNode.insertBefore(label, this);
if (this.classList.contains('emby-select-withcolor')) {
this.parentNode.insertAdjacentHTML('beforeend', '<div class="selectArrowContainer"><div style="visibility:hidden;">0</div><i class="selectArrow md-icon">&#xE313;</i></div>');
}
};
EmbySelectPrototype.setLabel = function (text) {
var label = this.parentNode.querySelector('label');
label.innerHTML = text;
};
document.registerElement('emby-select', {
prototype: EmbySelectPrototype,
extends: "select"
})
extends: 'select'
});
});
@@ -1,7 +1,7 @@
_:-ms-input-placeholder {
-ms-appearance: none;
height: 2.223em;
margin: 0
margin: 0;
}
.mdl-slider {
@@ -11,7 +11,7 @@ _:-ms-input-placeholder {
-ms-appearance: none;
appearance: none;
height: .2em;
background: 0 0;
background: transparent;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
@@ -20,78 +20,79 @@ _:-ms-input-placeholder {
padding: 1em 0;
color: #00a4dc;
-webkit-align-self: center;
-ms-flex-item-align: center;
align-self: center;
z-index: 1;
cursor: pointer;
margin: 0;
-webkit-tap-highlight-color: transparent;
display: block
/* Disable webkit tap highlighting */
-webkit-tap-highlight-color: rgba(0,0,0,0);
display: block;
/**************************** Tracks ****************************/
/**************************** Thumbs ****************************/
/**************************** 0-value ****************************/
/**************************** Disabled ****************************/
}
.mdl-slider::-moz-focus-outer {
border: 0
}
.mdl-slider::-moz-focus-outer {
border: 0;
}
.mdl-slider::-ms-tooltip {
display: none
}
.mdl-slider::-ms-tooltip {
display: none;
}
.mdl-slider::-webkit-slider-runnable-track {
background: 0 0
}
.mdl-slider::-webkit-slider-runnable-track {
background: transparent;
}
.mdl-slider::-moz-range-track {
background: #444;
border: none
}
.mdl-slider::-moz-range-track {
background: #444;
border: none;
}
.mdl-slider::-moz-range-progress {
background: #00a4dc
}
.mdl-slider::-moz-range-progress {
background: #00a4dc;
}
.mdl-slider::-ms-track {
background: 0 0;
color: transparent;
height: .2em;
width: 100%;
border: none
}
.mdl-slider::-ms-track {
background: none;
color: transparent;
height: .2em;
width: 100%;
border: none;
}
.mdl-slider::-ms-fill-lower {
display: none
}
.mdl-slider::-ms-fill-lower {
display: none;
}
.mdl-slider::-ms-fill-upper {
display: none
}
.mdl-slider::-ms-fill-upper {
display: none;
}
.mdl-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 1.8em;
height: 1.8em;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 50%;
border-radius: 50%;
background: #00a4dc;
border: none;
-webkit-transition: -webkit-transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), -webkit-box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1);
transition: transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1)
}
.mdl-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 1.8em;
height: 1.8em;
box-sizing: border-box;
border-radius: 50%;
background: #00a4dc;
border: none;
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}
.mdl-slider-hoverthumb::-webkit-slider-thumb {
margin-left: -.12em;
-webkit-transform: scale(.7, .7);
transform: scale(.7, .7)
transform: scale(.7, .7);
}
.mdl-slider:hover::-webkit-slider-thumb {
-webkit-transform: none;
transform: none
transform: none;
}
.slider-no-webkit-thumb::-webkit-slider-thumb {
opacity: 0 !important
opacity: 0 !important;
}
.mdl-slider::-moz-range-thumb {
@@ -100,8 +101,9 @@ _:-ms-input-placeholder {
height: 1.8em;
box-sizing: border-box;
border-radius: 50%;
background-image: none;
background: #00a4dc;
border: none
border: none;
}
.mdl-slider::-ms-thumb {
@@ -112,28 +114,28 @@ _:-ms-input-placeholder {
border-radius: 50%;
background: #00a4dc;
border: none;
transition: transform .3s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1)
transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1), border 0.18s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.18s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}
.mdl-slider-hoverthumb::-ms-thumb {
margin-left: -.4em;
transform: scale(.5, .5)
transform: scale(.5, .5);
}
.mdl-slider:hover::-ms-thumb {
transform: none
transform: none;
}
.mdl-slider[disabled]::-webkit-slider-thumb {
display: none
display: none;
}
.mdl-slider[disabled]::-moz-range-thumb {
display: none
display: none;
}
.mdl-slider[disabled]::-ms-thumb {
display: none
display: none;
}
.mdl-slider-ie-container {
@@ -141,20 +143,15 @@ _:-ms-input-placeholder {
overflow: visible;
border: none;
margin: 0;
padding: 0
padding: 0;
}
.mdl-slider-container {
height: 1.25em;
position: relative;
background: 0 0;
display: -webkit-box;
display: -webkit-flex;
background: none;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row
flex-direction: row;
}
.mdl-slider-background-flex {
@@ -165,70 +162,62 @@ _:-ms-input-placeholder {
width: 100%;
top: 50%;
left: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex;
overflow: hidden;
border: 0;
padding: 0
padding: 0;
}
.mdl-slider-background-flex-inner {
position: relative;
width: 100%
width: 100%;
}
.mdl-slider-background-lower {
/*transition: width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
position: absolute;
left: 0;
width: 0;
top: 0;
bottom: 0;
background-color: #00a4dc
background-color: #00a4dc;
}
.mdl-slider-background-lower-clear {
background-color: transparent
background-color: transparent;
}
.mdl-slider-background-lower-withtransform {
width: 100%;
-webkit-transform-origin: left center;
/*transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
transform-origin: left center;
-webkit-transform: scaleX(0);
transform: scaleX(0)
transform: scaleX(0);
}
.mdl-slider-background-upper {
/*transition: left 0.18s cubic-bezier(0.4, 0, 0.2, 1), width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/
background: #666;
background: rgba(255, 255, 255, .4);
position: absolute;
left: 0;
width: 0;
top: 0;
bottom: 0
bottom: 0;
}
.sliderBubble {
position: absolute;
top: 0;
left: 0;
-webkit-transform: translate3d(-48%, -120%, 0);
transform: translate3d(-48%, -120%, 0);
background: #282828;
color: #fff;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center
justify-content: center;
}
.sliderBubbleText {
margin: 0;
padding: .5em .75em
}
padding: .5em .75em;
}
@@ -1,101 +1,270 @@
define(["browser", "dom", "layoutManager", "css!./emby-slider", "registerElement", "emby-input"], function(browser, dom, layoutManager) {
"use strict";
define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager) {
'use strict';
var EmbySliderPrototype = Object.create(HTMLInputElement.prototype);
var supportsNativeProgressStyle = browser.firefox;
var supportsValueSetOverride = false;
var enableWidthWithTransform;
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
// descriptor returning null in webos
if (descriptor && descriptor.configurable) {
supportsValueSetOverride = true;
}
}
function updateValues() {
var range = this,
value = range.value;
requestAnimationFrame(function() {
var range = this;
var value = range.value;
// put this on a callback. Doing it within the event sometimes causes the slider to get hung up and not respond
requestAnimationFrame(function () {
var backgroundLower = range.backgroundLower;
if (backgroundLower) {
var fraction = (value - range.min) / (range.max - range.min);
enableWidthWithTransform ? backgroundLower.style.transform = "scaleX(" + fraction + ")" : (fraction *= 100, backgroundLower.style.width = fraction + "%")
if (enableWidthWithTransform) {
backgroundLower.style.transform = 'scaleX(' + (fraction) + ')';
} else {
fraction *= 100;
backgroundLower.style.width = fraction + '%';
}
}
})
});
}
function updateBubble(range, value, bubble, bubbleText) {
requestAnimationFrame(function() {
bubble.style.left = value + "%", range.getBubbleHtml ? value = range.getBubbleHtml(value) : (value = range.getBubbleText ? range.getBubbleText(value) : Math.round(value), value = '<h1 class="sliderBubbleText">' + value + "</h1>"), bubble.innerHTML = value
})
requestAnimationFrame(function () {
bubble.style.left = value + '%';
if (range.getBubbleHtml) {
value = range.getBubbleHtml(value);
} else {
if (range.getBubbleText) {
value = range.getBubbleText(value);
} else {
value = Math.round(value);
}
value = '<h1 class="sliderBubbleText">' + value + '</h1>';
}
bubble.innerHTML = value;
});
}
EmbySliderPrototype.attachedCallback = function () {
if (this.getAttribute('data-embyslider') === 'true') {
return;
}
if (enableWidthWithTransform == null) {
//enableWidthWithTransform = browser.supportsCssAnimation();
}
this.setAttribute('data-embyslider', 'true');
this.classList.add('mdl-slider');
this.classList.add('mdl-js-slider');
if (browser.noFlex) {
this.classList.add('slider-no-webkit-thumb');
}
if (!layoutManager.mobile) {
this.classList.add('mdl-slider-hoverthumb');
}
var containerElement = this.parentNode;
containerElement.classList.add('mdl-slider-container');
var htmlToInsert = '';
if (!supportsNativeProgressStyle) {
htmlToInsert += '<div class="mdl-slider-background-flex">';
htmlToInsert += '<div class="mdl-slider-background-flex-inner">';
// the more of these, the more ranges we can display
htmlToInsert += '<div class="mdl-slider-background-upper"></div>';
if (enableWidthWithTransform) {
htmlToInsert += '<div class="mdl-slider-background-lower mdl-slider-background-lower-withtransform"></div>';
} else {
htmlToInsert += '<div class="mdl-slider-background-lower"></div>';
}
htmlToInsert += '</div>';
htmlToInsert += '</div>';
}
htmlToInsert += '<div class="sliderBubble hide"></div>';
containerElement.insertAdjacentHTML('beforeend', htmlToInsert);
this.backgroundLower = containerElement.querySelector('.mdl-slider-background-lower');
this.backgroundUpper = containerElement.querySelector('.mdl-slider-background-upper');
var sliderBubble = containerElement.querySelector('.sliderBubble');
var hasHideClass = sliderBubble.classList.contains('hide');
dom.addEventListener(this, 'input', function (e) {
this.dragging = true;
updateBubble(this, this.value, sliderBubble);
if (hasHideClass) {
sliderBubble.classList.remove('hide');
hasHideClass = false;
}
}, {
passive: true
});
dom.addEventListener(this, 'change', function () {
this.dragging = false;
updateValues.call(this);
sliderBubble.classList.add('hide');
hasHideClass = true;
}, {
passive: true
});
// In firefox this feature disrupts the ability to move the slider
if (!browser.firefox) {
dom.addEventListener(this, (window.PointerEvent ? 'pointermove' : 'mousemove'), function (e) {
if (!this.dragging) {
var rect = this.getBoundingClientRect();
var clientX = e.clientX;
var bubbleValue = (clientX - rect.left) / rect.width;
bubbleValue *= 100;
updateBubble(this, bubbleValue, sliderBubble);
if (hasHideClass) {
sliderBubble.classList.remove('hide');
hasHideClass = false;
}
}
}, {
passive: true
});
dom.addEventListener(this, (window.PointerEvent ? 'pointerleave' : 'mouseleave'), function () {
sliderBubble.classList.add('hide');
hasHideClass = true;
}, {
passive: true
});
}
if (!supportsNativeProgressStyle) {
if (supportsValueSetOverride) {
this.addEventListener('valueset', updateValues);
} else {
startInterval(this);
}
}
};
function setRange(elem, startPercent, endPercent) {
var style = elem.style;
style.left = Math.max(startPercent, 0) + "%";
style.left = Math.max(startPercent, 0) + '%';
var widthPercent = endPercent - startPercent;
style.width = Math.max(Math.min(widthPercent, 100), 0) + "%"
style.width = Math.max(Math.min(widthPercent, 100), 0) + '%';
}
function mapRangesFromRuntimeToPercent(ranges, runtime) {
return runtime ? ranges.map(function(r) {
if (!runtime) {
return [];
}
return ranges.map(function (r) {
return {
start: r.start / runtime * 100,
end: r.end / runtime * 100
}
}) : []
start: (r.start / runtime) * 100,
end: (r.end / runtime) * 100
};
});
}
EmbySliderPrototype.setBufferedRanges = function (ranges, runtime, position) {
var elem = this.backgroundUpper;
if (!elem) {
return;
}
if (runtime != null) {
ranges = mapRangesFromRuntimeToPercent(ranges, runtime);
position = (position / runtime) * 100;
}
for (var i = 0, length = ranges.length; i < length; i++) {
var range = ranges[i];
if (position != null) {
if (position >= range.end) {
continue;
}
}
setRange(elem, range.start, range.end);
return;
}
setRange(elem, 0, 0);
};
EmbySliderPrototype.setIsClear = function (isClear) {
var backgroundLower = this.backgroundLower;
if (backgroundLower) {
if (isClear) {
backgroundLower.classList.add('mdl-slider-background-lower-clear');
} else {
backgroundLower.classList.remove('mdl-slider-background-lower-clear');
}
}
};
function startInterval(range) {
var interval = range.interval;
interval && clearInterval(interval), range.interval = setInterval(updateValues.bind(range), 100)
}
var enableWidthWithTransform, EmbySliderPrototype = Object.create(HTMLInputElement.prototype),
supportsNativeProgressStyle = browser.firefox,
supportsValueSetOverride = !1;
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
descriptor && descriptor.configurable && (supportsValueSetOverride = !0)
}
EmbySliderPrototype.attachedCallback = function() {
if ("true" !== this.getAttribute("data-embyslider")) {
this.setAttribute("data-embyslider", "true"), this.classList.add("mdl-slider"), this.classList.add("mdl-js-slider"), browser.noFlex && this.classList.add("slider-no-webkit-thumb"), layoutManager.mobile || this.classList.add("mdl-slider-hoverthumb");
var containerElement = this.parentNode;
containerElement.classList.add("mdl-slider-container");
var htmlToInsert = "";
supportsNativeProgressStyle || (htmlToInsert += '<div class="mdl-slider-background-flex">', htmlToInsert += '<div class="mdl-slider-background-flex-inner">', htmlToInsert += '<div class="mdl-slider-background-upper"></div>', htmlToInsert += enableWidthWithTransform ? '<div class="mdl-slider-background-lower mdl-slider-background-lower-withtransform"></div>' : '<div class="mdl-slider-background-lower"></div>', htmlToInsert += "</div>", htmlToInsert += "</div>"), htmlToInsert += '<div class="sliderBubble hide"></div>', containerElement.insertAdjacentHTML("beforeend", htmlToInsert), this.backgroundLower = containerElement.querySelector(".mdl-slider-background-lower"), this.backgroundUpper = containerElement.querySelector(".mdl-slider-background-upper");
var sliderBubble = containerElement.querySelector(".sliderBubble"),
hasHideClass = sliderBubble.classList.contains("hide");
dom.addEventListener(this, "input", function(e) {
this.dragging = !0, updateBubble(this, this.value, sliderBubble), hasHideClass && (sliderBubble.classList.remove("hide"), hasHideClass = !1)
}, {
passive: !0
}), dom.addEventListener(this, "change", function() {
this.dragging = !1, updateValues.call(this), sliderBubble.classList.add("hide"), hasHideClass = !0
}, {
passive: !0
}), browser.firefox || (dom.addEventListener(this, window.PointerEvent ? "pointermove" : "mousemove", function(e) {
if (!this.dragging) {
var rect = this.getBoundingClientRect(),
clientX = e.clientX,
bubbleValue = (clientX - rect.left) / rect.width;
bubbleValue *= 100, updateBubble(this, bubbleValue, sliderBubble), hasHideClass && (sliderBubble.classList.remove("hide"), hasHideClass = !1)
}
}, {
passive: !0
}), dom.addEventListener(this, window.PointerEvent ? "pointerleave" : "mouseleave", function() {
sliderBubble.classList.add("hide"), hasHideClass = !0
}, {
passive: !0
})), supportsNativeProgressStyle || (supportsValueSetOverride ? this.addEventListener("valueset", updateValues) : startInterval(this))
if (interval) {
clearInterval(interval);
}
}, EmbySliderPrototype.setBufferedRanges = function(ranges, runtime, position) {
var elem = this.backgroundUpper;
if (elem) {
null != runtime && (ranges = mapRangesFromRuntimeToPercent(ranges, runtime), position = position / runtime * 100);
for (var i = 0, length = ranges.length; i < length; i++) {
var range = ranges[i];
if (!(null != position && position >= range.end)) return void setRange(elem, range.start, range.end)
}
setRange(elem, 0, 0)
}
}, EmbySliderPrototype.setIsClear = function(isClear) {
var backgroundLower = this.backgroundLower;
backgroundLower && (isClear ? backgroundLower.classList.add("mdl-slider-background-lower-clear") : backgroundLower.classList.remove("mdl-slider-background-lower-clear"))
}, EmbySliderPrototype.detachedCallback = function() {
range.interval = setInterval(updateValues.bind(range), 100);
}
EmbySliderPrototype.detachedCallback = function () {
var interval = this.interval;
interval && clearInterval(interval), this.interval = null, this.backgroundUpper = null, this.backgroundLower = null
}, document.registerElement("emby-slider", {
if (interval) {
clearInterval(interval);
}
this.interval = null;
this.backgroundUpper = null;
this.backgroundLower = null;
};
document.registerElement('emby-slider', {
prototype: EmbySliderPrototype,
extends: "input"
})
extends: 'input'
});
});
@@ -1,43 +1,47 @@
.emby-tab-button,
.emby-tabs-slider {
position: relative
}
.emby-tab-button {
background: 0 0;
-webkit-box-shadow: none;
.emby-tab-button {
background: transparent;
box-shadow: none;
cursor: pointer;
outline: 0 !important;
outline: none !important;
width: auto;
font-family: inherit;
font-size: inherit;
display: inline-block;
vertical-align: middle;
-webkit-flex-shrink: 0;
flex-shrink: 0;
margin: 0;
padding: 1em .9em;
position: relative;
height: auto;
min-width: initial;
line-height: initial;
-webkit-border-radius: 0 !important;
border-radius: 0 !important;
overflow: hidden;
font-weight: 600
font-weight: 600;
}
.emby-tab-button.emby-button-tv:focus {
-webkit-transform: scale(1.32);
transform: scale(1.32);
-webkit-transform-origin: center center;
transform-origin: center center
/*.emby-tab-button-active {
color: #52B54B;
}
.emby-tab-button-active.emby-button-tv {
color: #fff;
}*/
.emby-tab-button.emby-button-tv:focus {
/*color: #52B54B;*/
transform: scale(1.32);
transform-origin: center center;
}
.emby-tabs-slider {
position: relative;
}
.emby-tab-button-ripple-effect {
background: rgba(0, 0, 0, .7) !important
background: rgba(0,0,0,.7) !important;
}
.tabContent:not(.is-active) {
display: none
}
display: none;
}
+294 -115
View File
@@ -1,191 +1,370 @@
define(["dom", "scroller", "browser", "layoutManager", "focusManager", "registerElement", "css!./emby-tabs", "scrollStyles"], function(dom, scroller, browser, layoutManager, focusManager) {
"use strict";
define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
'use strict';
var EmbyTabs = Object.create(HTMLDivElement.prototype);
var buttonClass = 'emby-tab-button';
var activeButtonClass = buttonClass + '-active';
function setActiveTabButton(tabs, newButton, oldButton, animate) {
newButton.classList.add(activeButtonClass)
newButton.classList.add(activeButtonClass);
}
function getFocusCallback(tabs, e) {
return function() {
onClick.call(tabs, e)
}
return function () {
onClick.call(tabs, e);
};
}
function onFocus(e) {
layoutManager.tv && (this.focusTimeout && clearTimeout(this.focusTimeout), this.focusTimeout = setTimeout(getFocusCallback(this, e), 700))
if (layoutManager.tv) {
if (this.focusTimeout) {
clearTimeout(this.focusTimeout);
}
this.focusTimeout = setTimeout(getFocusCallback(this, e), 700);
}
}
function getTabPanel(tabs, index) {
return null
return null;
}
function removeActivePanelClass(tabs, index) {
var tabPanel = getTabPanel(tabs, index);
tabPanel && tabPanel.classList.remove("is-active")
if (tabPanel) {
tabPanel.classList.remove('is-active');
}
}
function addActivePanelClass(tabs, index) {
var tabPanel = getTabPanel(tabs, index);
if (tabPanel) {
tabPanel.classList.add('is-active');
}
}
function fadeInRight(elem) {
var pct = browser.mobile ? "4%" : "0.5%",
keyframes = [{
opacity: "0",
transform: "translate3d(" + pct + ", 0, 0)",
offset: 0
}, {
opacity: "1",
transform: "none",
offset: 1
}];
var pct = browser.mobile ? '4%' : '0.5%';
var keyframes = [
{ opacity: '0', transform: 'translate3d(' + pct + ', 0, 0)', offset: 0 },
{ opacity: '1', transform: 'none', offset: 1 }];
elem.animate(keyframes, {
duration: 160,
iterations: 1,
easing: "ease-out"
})
easing: 'ease-out'
});
}
function triggerBeforeTabChange(tabs, index, previousIndex) {
tabs.dispatchEvent(new CustomEvent("beforetabchange", {
detail: {
selectedTabIndex: index,
previousIndex: previousIndex
}
})), null != previousIndex && previousIndex !== index && removeActivePanelClass(tabs, previousIndex);
}));
if (previousIndex != null && previousIndex !== index) {
removeActivePanelClass(tabs, previousIndex);
}
var newPanel = getTabPanel(tabs, index);
newPanel && (newPanel.animate && fadeInRight(newPanel), newPanel.classList.add("is-active"))
if (newPanel) {
// animate new panel ?
if (newPanel.animate) {
fadeInRight(newPanel);
}
newPanel.classList.add('is-active');
}
}
function onClick(e) {
this.focusTimeout && clearTimeout(this.focusTimeout);
var tabs = this,
current = tabs.querySelector("." + activeButtonClass),
tabButton = dom.parentWithClass(e.target, buttonClass);
if (this.focusTimeout) {
clearTimeout(this.focusTimeout);
}
var tabs = this;
var current = tabs.querySelector('.' + activeButtonClass);
var tabButton = dom.parentWithClass(e.target, buttonClass);
if (tabButton && tabButton !== current) {
current && current.classList.remove(activeButtonClass);
var previousIndex = current ? parseInt(current.getAttribute("data-index")) : null;
setActiveTabButton(tabs, tabButton, current, !0);
var index = parseInt(tabButton.getAttribute("data-index"));
triggerBeforeTabChange(tabs, index, previousIndex), setTimeout(function() {
tabs.selectedTabIndex = index, tabs.dispatchEvent(new CustomEvent("tabchange", {
if (current) {
current.classList.remove(activeButtonClass);
}
var previousIndex = current ? parseInt(current.getAttribute('data-index')) : null;
setActiveTabButton(tabs, tabButton, current, true);
var index = parseInt(tabButton.getAttribute('data-index'));
triggerBeforeTabChange(tabs, index, previousIndex);
// If toCenter is called syncronously within the click event, it sometimes ends up canceling it
setTimeout(function () {
tabs.selectedTabIndex = index;
tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: {
selectedTabIndex: index,
previousIndex: previousIndex
}
}))
}, 120), tabs.scroller && tabs.scroller.toCenter(tabButton, !1)
}));
}, 120);
if (tabs.scroller) {
tabs.scroller.toCenter(tabButton, false);
}
}
}
function initScroller(tabs) {
if (!tabs.scroller) {
var contentScrollSlider = tabs.querySelector(".emby-tabs-slider");
contentScrollSlider ? (tabs.scroller = new scroller(tabs, {
if (tabs.scroller) {
return;
}
var contentScrollSlider = tabs.querySelector('.emby-tabs-slider');
if (contentScrollSlider) {
tabs.scroller = new scroller(tabs, {
horizontal: 1,
itemNav: 0,
mouseDragging: 1,
touchDragging: 1,
slidee: contentScrollSlider,
smart: !0,
releaseSwing: !0,
smart: true,
releaseSwing: true,
scrollBy: 200,
speed: 120,
elasticBounds: 1,
dragHandle: 1,
dynamicHandle: 1,
clickBar: 1,
hiddenScroll: !0,
hiddenScroll: true,
// In safari the transform is causing the headers to occasionally disappear or flicker
requireAnimation: !browser.safari,
allowNativeSmoothScroll: !0
}), tabs.scroller.init()) : (tabs.classList.add("scrollX"), tabs.classList.add("hiddenScrollX"), tabs.classList.add("smoothScrollX"))
}
allowNativeSmoothScroll: true
});
tabs.scroller.init();
} else {
tabs.classList.add('scrollX');
tabs.classList.add('hiddenScrollX');
tabs.classList.add('smoothScrollX');
}
}
EmbyTabs.createdCallback = function () {
if (this.classList.contains('emby-tabs')) {
return;
}
this.classList.add('emby-tabs');
this.classList.add('focusable');
dom.addEventListener(this, 'click', onClick, {
passive: true
});
dom.addEventListener(this, 'focus', onFocus, {
passive: true,
capture: true
});
};
EmbyTabs.focus = function () {
var selected = this.querySelector('.' + activeButtonClass);
if (selected) {
focusManager.focus(selected);
} else {
focusManager.autoFocus(this);
}
};
EmbyTabs.refresh = function () {
if (this.scroller) {
this.scroller.reload();
}
};
EmbyTabs.attachedCallback = function () {
initScroller(this);
var current = this.querySelector('.' + activeButtonClass);
var currentIndex = current ? parseInt(current.getAttribute('data-index')) : parseInt(this.getAttribute('data-index') || '0');
if (currentIndex !== -1) {
this.selectedTabIndex = currentIndex;
var tabButtons = this.querySelectorAll('.' + buttonClass);
var newTabButton = tabButtons[currentIndex];
if (newTabButton) {
setActiveTabButton(this, newTabButton, current, false);
}
}
if (!this.readyFired) {
this.readyFired = true;
this.dispatchEvent(new CustomEvent("ready", {}));
}
};
EmbyTabs.detachedCallback = function () {
if (this.scroller) {
this.scroller.destroy();
this.scroller = null;
}
dom.removeEventListener(this, 'click', onClick, {
passive: true
});
dom.removeEventListener(this, 'focus', onFocus, {
passive: true,
capture: true
});
};
function getSelectedTabButton(elem) {
return elem.querySelector("." + activeButtonClass)
return elem.querySelector('.' + activeButtonClass);
}
function getSibling(elem, method) {
for (var sibling = elem[method]; sibling;) {
if (sibling.classList.contains(buttonClass) && !sibling.classList.contains("hide")) return sibling;
sibling = sibling[method]
}
return null
}
var EmbyTabs = Object.create(HTMLDivElement.prototype),
buttonClass = "emby-tab-button",
activeButtonClass = buttonClass + "-active";
EmbyTabs.createdCallback = function() {
this.classList.contains("emby-tabs") || (this.classList.add("emby-tabs"), this.classList.add("focusable"), dom.addEventListener(this, "click", onClick, {
passive: !0
}), dom.addEventListener(this, "focus", onFocus, {
passive: !0,
capture: !0
}))
}, EmbyTabs.focus = function() {
var selected = this.querySelector("." + activeButtonClass);
selected ? focusManager.focus(selected) : focusManager.autoFocus(this)
}, EmbyTabs.refresh = function() {
this.scroller && this.scroller.reload()
}, EmbyTabs.attachedCallback = function() {
initScroller(this);
var current = this.querySelector("." + activeButtonClass),
currentIndex = current ? parseInt(current.getAttribute("data-index")) : parseInt(this.getAttribute("data-index") || "0");
if (-1 !== currentIndex) {
this.selectedTabIndex = currentIndex;
var tabButtons = this.querySelectorAll("." + buttonClass),
newTabButton = tabButtons[currentIndex];
newTabButton && setActiveTabButton(this, newTabButton, current, !1)
}
this.readyFired || (this.readyFired = !0, this.dispatchEvent(new CustomEvent("ready", {})))
}, EmbyTabs.detachedCallback = function() {
this.scroller && (this.scroller.destroy(), this.scroller = null), dom.removeEventListener(this, "click", onClick, {
passive: !0
}), dom.removeEventListener(this, "focus", onFocus, {
passive: !0,
capture: !0
})
}, EmbyTabs.selectedIndex = function(selected, triggerEvent) {
EmbyTabs.selectedIndex = function (selected, triggerEvent) {
var tabs = this;
if (null == selected) return tabs.selectedTabIndex || 0;
if (selected == null) {
return tabs.selectedTabIndex || 0;
}
var current = tabs.selectedIndex();
tabs.selectedTabIndex = selected;
var tabButtons = tabs.querySelectorAll("." + buttonClass);
if (current === selected || !1 === triggerEvent) {
triggerBeforeTabChange(tabs, selected, current), tabs.dispatchEvent(new CustomEvent("tabchange", {
var tabButtons = tabs.querySelectorAll('.' + buttonClass);
if (current === selected || triggerEvent === false) {
triggerBeforeTabChange(tabs, selected, current);
tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: {
selectedTabIndex: selected
}
}));
var currentTabButton = tabButtons[current];
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, !1), current !== selected && currentTabButton && currentTabButton.classList.remove(activeButtonClass)
} else onClick.call(tabs, {
target: tabButtons[selected]
})
}, EmbyTabs.selectNext = function() {
var current = getSelectedTabButton(this),
sibling = getSibling(current, "nextSibling");
sibling && onClick.call(this, {
target: sibling
})
}, EmbyTabs.selectPrevious = function() {
var current = getSelectedTabButton(this),
sibling = getSibling(current, "previousSibling");
sibling && onClick.call(this, {
target: sibling
})
}, EmbyTabs.triggerBeforeTabChange = function(selected) {
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false);
if (current !== selected && currentTabButton) {
currentTabButton.classList.remove(activeButtonClass);
}
} else {
onClick.call(tabs, {
target: tabButtons[selected]
});
//tabButtons[selected].click();
}
};
function getSibling(elem, method) {
var sibling = elem[method];
while (sibling) {
if (sibling.classList.contains(buttonClass)) {
if (!sibling.classList.contains('hide')) {
return sibling;
}
}
sibling = sibling[method];
}
return null;
}
EmbyTabs.selectNext = function () {
var current = getSelectedTabButton(this);
var sibling = getSibling(current, 'nextSibling');
if (sibling) {
onClick.call(this, {
target: sibling
});
}
};
EmbyTabs.selectPrevious = function () {
var current = getSelectedTabButton(this);
var sibling = getSibling(current, 'previousSibling');
if (sibling) {
onClick.call(this, {
target: sibling
});
}
};
EmbyTabs.triggerBeforeTabChange = function (selected) {
var tabs = this;
triggerBeforeTabChange(tabs, tabs.selectedIndex())
}, EmbyTabs.triggerTabChange = function(selected) {
triggerBeforeTabChange(tabs, tabs.selectedIndex());
};
EmbyTabs.triggerTabChange = function (selected) {
var tabs = this;
tabs.dispatchEvent(new CustomEvent("tabchange", {
detail: {
selectedTabIndex: tabs.selectedIndex()
}
}))
}, EmbyTabs.setTabEnabled = function(index, enabled) {
}));
};
EmbyTabs.setTabEnabled = function (index, enabled) {
var tabs = this;
var btn = this.querySelector('.emby-tab-button[data-index="' + index + '"]');
enabled ? btn.classList.remove("hide") : btn.classList.remove("add")
}, document.registerElement("emby-tabs", {
if (enabled) {
btn.classList.remove('hide');
} else {
btn.classList.remove('add');
}
};
document.registerElement('emby-tabs', {
prototype: EmbyTabs,
extends: "div"
})
extends: 'div'
});
});
@@ -2,30 +2,31 @@
display: block;
margin: 0;
margin-bottom: 0 !important;
/* Remove select styling */
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
font-size: inherit;
/* General select styles: change as needed */
font-family: inherit;
font-weight: inherit;
color: inherit;
padding: .35em .25em;
-webkit-box-sizing: border-box;
/* Prevent padding from causing width overflow */
box-sizing: border-box;
outline: 0 !important;
-webkit-tap-highlight-color: transparent;
width: 100%
outline: none !important;
-webkit-tap-highlight-color: rgba(0,0,0,0);
width: 100%;
}
.emby-textarea::-moz-focus-inner {
border: 0
}
.emby-textarea::-moz-focus-inner {
border: 0;
}
.textareaLabel {
display: inline-block;
-webkit-transition: all .2s ease-out;
-o-transition: all .2s ease-out;
transition: all .2s ease-out;
margin-bottom: .25em
margin-bottom: .25em;
}
.emby-textarea+.fieldDescription {
margin-top: .25em
}
.emby-textarea + .fieldDescription {
margin-top: .25em;
}
@@ -1,55 +1,138 @@
define(["layoutManager", "browser", "css!./emby-textarea", "registerElement", "emby-input"], function(layoutManager, browser) {
"use strict";
define(['layoutManager', 'browser', 'css!./emby-textarea', 'registerElement', 'emby-input'], function (layoutManager, browser) {
'use strict';
function autoGrow(textarea, maxLines) {
var self = this;
if (maxLines === undefined) {
maxLines = 999;
}
/**
* Calculates the vertical padding of the element
* @param textarea
* @returns {number}
*/
self.getOffset = function (textarea) {
var style = window.getComputedStyle(textarea, null),
props = ['paddingTop', 'paddingBottom'],
offset = 0;
for (var i = 0; i < props.length; i++) {
offset += parseInt(style[props[i]]);
}
return offset;
};
var offset;
function reset() {
textarea.rows = 1, offset = self.getOffset(textarea), self.rows = textarea.rows || 1, self.lineHeight = textarea.scrollHeight / self.rows - offset / self.rows, self.maxAllowedHeight = self.lineHeight * maxLines - offset
textarea.rows = 1;
offset = self.getOffset(textarea);
self.rows = textarea.rows || 1;
self.lineHeight = (textarea.scrollHeight / self.rows) - (offset / self.rows);
self.maxAllowedHeight = (self.lineHeight * maxLines) - offset;
}
function autogrowFn() {
if ((!self.lineHeight || self.lineHeight <= 0) && reset(), self.lineHeight <= 0) return textarea.style.overflowY = "scroll", textarea.style.height = "auto", void(textarea.rows = 3);
var newHeight = 0;
textarea.scrollHeight - offset > self.maxAllowedHeight ? (textarea.style.overflowY = "scroll", newHeight = self.maxAllowedHeight) : (textarea.style.overflowY = "hidden", textarea.style.height = "auto", newHeight = textarea.scrollHeight), textarea.style.height = newHeight + "px"
if (!self.lineHeight || self.lineHeight <= 0) {
reset();
}
if (self.lineHeight <= 0) {
textarea.style.overflowY = 'scroll';
textarea.style.height = 'auto';
textarea.rows = 3;
return;
}
var newHeight = 0, hasGrown = false;
if ((textarea.scrollHeight - offset) > self.maxAllowedHeight) {
textarea.style.overflowY = 'scroll';
newHeight = self.maxAllowedHeight;
}
else {
textarea.style.overflowY = 'hidden';
textarea.style.height = 'auto';
newHeight = textarea.scrollHeight/* - offset*/;
hasGrown = true;
}
textarea.style.height = newHeight + 'px';
}
var self = this;
void 0 === maxLines && (maxLines = 999), self.getOffset = function(textarea) {
for (var style = window.getComputedStyle(textarea, null), props = ["paddingTop", "paddingBottom"], offset = 0, i = 0; i < props.length; i++) offset += parseInt(style[props[i]]);
return offset
};
var offset;
textarea.addEventListener("input", autogrowFn), textarea.addEventListener("focus", autogrowFn), textarea.addEventListener("valueset", autogrowFn), autogrowFn()
// Call autogrowFn() when textarea's value is changed
textarea.addEventListener('input', autogrowFn);
textarea.addEventListener('focus', autogrowFn);
textarea.addEventListener('valueset', autogrowFn);
autogrowFn();
}
var EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype),
elementId = 0;
var EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype);
var elementId = 0;
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
var descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value");
var descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
// descriptor returning null in webos
if (descriptor && descriptor.configurable) {
var baseSetMethod = descriptor.set;
descriptor.set = function(value) {
baseSetMethod.call(this, value), this.dispatchEvent(new CustomEvent("valueset", {
bubbles: !1,
cancelable: !1
}))
}, Object.defineProperty(HTMLTextAreaElement.prototype, "value", descriptor)
descriptor.set = function (value) {
baseSetMethod.call(this, value);
this.dispatchEvent(new CustomEvent('valueset', {
bubbles: false,
cancelable: false
}));
};
Object.defineProperty(HTMLTextAreaElement.prototype, 'value', descriptor);
}
}
EmbyTextAreaPrototype.createdCallback = function() {
this.id || (this.id = "embytextarea" + elementId, elementId++)
}, EmbyTextAreaPrototype.attachedCallback = function() {
if (!this.classList.contains("emby-textarea")) {
this.rows = 1, this.classList.add("emby-textarea");
var parentNode = this.parentNode,
label = this.ownerDocument.createElement("label");
label.innerHTML = this.getAttribute("label") || "", label.classList.add("textareaLabel"), label.htmlFor = this.id, parentNode.insertBefore(label, this), this.addEventListener("focus", function() {
label.classList.add("textareaLabelFocused"), label.classList.remove("textareaLabelUnfocused")
}), this.addEventListener("blur", function() {
label.classList.remove("textareaLabelFocused"), label.classList.add("textareaLabelUnfocused")
}), this.label = function(text) {
label.innerHTML = text
}, new autoGrow(this)
EmbyTextAreaPrototype.createdCallback = function () {
if (!this.id) {
this.id = 'embytextarea' + elementId;
elementId++;
}
}, document.registerElement("emby-textarea", {
};
EmbyTextAreaPrototype.attachedCallback = function () {
if (this.classList.contains('emby-textarea')) {
return;
}
this.rows = 1;
this.classList.add('emby-textarea');
var parentNode = this.parentNode;
var label = this.ownerDocument.createElement('label');
label.innerHTML = this.getAttribute('label') || '';
label.classList.add('textareaLabel');
label.htmlFor = this.id;
parentNode.insertBefore(label, this);
this.addEventListener('focus', function () {
label.classList.add('textareaLabelFocused');
label.classList.remove('textareaLabelUnfocused');
});
this.addEventListener('blur', function () {
label.classList.remove('textareaLabelFocused');
label.classList.add('textareaLabelUnfocused');
});
this.label = function (text) {
label.innerHTML = text;
};
new autoGrow(this);
};
document.registerElement('emby-textarea', {
prototype: EmbyTextAreaPrototype,
extends: "textarea"
})
extends: 'textarea'
});
});
@@ -2,13 +2,8 @@
position: relative;
z-index: 1;
vertical-align: middle;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
margin: 0;
@@ -19,17 +14,12 @@
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-box-orient: horizontal;
-webkit-box-direction: reverse;
-webkit-flex-direction: row-reverse;
flex-direction: row-reverse;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end
justify-content: flex-end;
}
.toggleContainer {
margin-bottom: 1.8em
margin-bottom: 1.8em;
}
.mdl-switch__input {
@@ -42,29 +32,28 @@
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
border: none
border: none;
}
.mdl-switch__trackContainer {
position: relative;
width: 2.9em
width: 2.9em;
}
.mdl-switch__track {
background: rgba(0, 0, 0, .2);
background: rgba(0,0,0, 0.2);
height: 1em;
-webkit-border-radius: 1em;
border-radius: 1em;
cursor: pointer
cursor: pointer;
}
.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track {
background: rgba(0,164,220, .5)
.mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track {
background: rgba(0, 164, 220, 0.5);
}
.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__track {
background: rgba(0, 0, 0, .12);
cursor: auto
.mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track {
background: rgba(0,0,0, 0.12);
cursor: auto;
}
.mdl-switch__thumb {
@@ -74,41 +63,26 @@
top: -.25em;
height: 1.44em;
width: 1.44em;
-webkit-border-radius: 50%;
border-radius: 50%;
cursor: pointer;
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
-webkit-transition-duration: .28s;
-o-transition-duration: .28s;
transition-duration: .28s;
-webkit-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
-o-transition-timing-function: cubic-bezier(.4, 0, .2, 1);
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
-webkit-transition-property: left;
-o-transition-property: left;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
transition-duration: 0.28s;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-property: left;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center
justify-content: center;
}
.mdl-switch__input:checked+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb {
.mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb {
background: #00a4dc;
left: 1.466em;
-webkit-box-shadow: 0 3px .28em 0 rgba(0, 0, 0, .14), 0 3px 3px -2px rgba(0, 0, 0, .2), 0 1px .56em 0 rgba(0, 0, 0, .12);
box-shadow: 0 3px .28em 0 rgba(0, 0, 0, .14), 0 3px 3px -2px rgba(0, 0, 0, .2), 0 1px .56em 0 rgba(0, 0, 0, .12)
box-shadow: 0 3px 0.28em 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.2), 0 1px .56em 0 rgba(0, 0, 0, 0.12);
}
.mdl-switch__input[disabled]+.mdl-switch__label+.mdl-switch__trackContainer>.mdl-switch__thumb {
background: #bdbdbd;
cursor: auto
.mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb {
background: rgb(189,189,189);
cursor: auto;
}
.mdl-switch__focus-helper {
@@ -118,38 +92,31 @@
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
display: inline-block;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: .6em;
height: .6em;
-webkit-border-radius: 50%;
border-radius: 50%;
background-color: transparent
background-color: transparent;
}
.mdl-switch__input:focus+.mdl-switch__label+.mdl-switch__trackContainer .mdl-switch__focus-helper {
-webkit-box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05);
box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05)
.mdl-switch__input:focus + .mdl-switch__label + .mdl-switch__trackContainer .mdl-switch__focus-helper {
box-shadow: 0 0 0 1.39em rgba(0, 0, 0, .05);
}
.mdl-switch__input:checked:focus+.mdl-switch__label+.mdl-switch__trackContainer .mdl-switch__focus-helper {
-webkit-box-shadow: 0 0 0 1.39em rgba(0,164,220, .26);
box-shadow: 0 0 0 1.39em rgba(0,164,220, .26);
background-color: rgba(0,164,220, .26)
.mdl-switch__input:checked:focus + .mdl-switch__label + .mdl-switch__trackContainer .mdl-switch__focus-helper {
box-shadow: 0 0 0 1.39em rgba(0, 164, 220, 0.26);
background-color: rgba(0, 164, 220, 0.26);
}
.mdl-switch__label {
cursor: pointer;
margin: 0 0 0 .7em;
display: -webkit-inline-box;
display: -webkit-inline-flex;
margin: 0;
display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center
align-items: center;
margin-left: .7em;
}
.mdl-switch__input[disabled] .mdl-switch__label {
color: #bdbdbd;
cursor: auto
}
color: rgb(189,189,189);
cursor: auto;
}
@@ -1,22 +1,50 @@
define(["css!./emby-toggle", "registerElement"], function() {
"use strict";
define(['css!./emby-toggle', 'registerElement'], function () {
'use strict';
var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype);
function onKeyDown(e) {
if (13 === e.keyCode) return e.preventDefault(), this.checked = !this.checked, this.dispatchEvent(new CustomEvent("change", {
bubbles: !0
})), !1
}
var EmbyTogglePrototype = Object.create(HTMLInputElement.prototype);
EmbyTogglePrototype.attachedCallback = function() {
if ("true" !== this.getAttribute("data-embytoggle")) {
this.setAttribute("data-embytoggle", "true"), this.classList.add("mdl-switch__input");
var labelElement = this.parentNode;
labelElement.classList.add("mdl-switch"), labelElement.classList.add("mdl-js-switch");
var labelTextElement = labelElement.querySelector("span");
labelElement.insertAdjacentHTML("beforeend", '<div class="mdl-switch__trackContainer"><div class="mdl-switch__track"></div><div class="mdl-switch__thumb"><span class="mdl-switch__focus-helper"></span></div></div>'), labelTextElement.classList.add("toggleButtonLabel"), labelTextElement.classList.add("mdl-switch__label"), this.addEventListener("keydown", onKeyDown)
// Don't submit form on enter
if (e.keyCode === 13) {
e.preventDefault();
this.checked = !this.checked;
this.dispatchEvent(new CustomEvent('change', {
bubbles: true
}));
return false;
}
}, document.registerElement("emby-toggle", {
}
EmbyTogglePrototype.attachedCallback = function () {
if (this.getAttribute('data-embytoggle') === 'true') {
return;
}
this.setAttribute('data-embytoggle', 'true');
this.classList.add('mdl-switch__input');
var labelElement = this.parentNode;
labelElement.classList.add('mdl-switch');
labelElement.classList.add('mdl-js-switch');
var labelTextElement = labelElement.querySelector('span');
labelElement.insertAdjacentHTML('beforeend', '<div class="mdl-switch__trackContainer"><div class="mdl-switch__track"></div><div class="mdl-switch__thumb"><span class="mdl-switch__focus-helper"></span></div></div>');
labelTextElement.classList.add('toggleButtonLabel');
labelTextElement.classList.add('mdl-switch__label');
this.addEventListener('keydown', onKeyDown);
};
document.registerElement('emby-toggle', {
prototype: EmbyTogglePrototype,
extends: "input"
})
extends: 'input'
});
});
+105 -27
View File
@@ -1,54 +1,132 @@
define([], function() {
"use strict";
define([], function () {
'use strict';
function getFetchPromise(request) {
var headers = request.headers || {};
"json" === request.dataType && (headers.accept = "application/json");
if (request.dataType === 'json') {
headers.accept = 'application/json';
}
var fetchRequest = {
headers: headers,
method: request.type,
credentials: "same-origin"
},
contentType = request.contentType;
request.data && ("string" == typeof request.data ? fetchRequest.body = request.data : (fetchRequest.body = paramsToString(request.data), contentType = contentType || "application/x-www-form-urlencoded; charset=UTF-8")), contentType && (headers["Content-Type"] = contentType);
headers: headers,
method: request.type,
credentials: 'same-origin'
};
var contentType = request.contentType;
if (request.data) {
if (typeof request.data === 'string') {
fetchRequest.body = request.data;
} else {
fetchRequest.body = paramsToString(request.data);
contentType = contentType || 'application/x-www-form-urlencoded; charset=UTF-8';
}
}
if (contentType) {
headers['Content-Type'] = contentType;
}
var url = request.url;
if (request.query) {
var paramString = paramsToString(request.query);
paramString && (url += "?" + paramString)
if (paramString) {
url += '?' + paramString;
}
}
return request.timeout ? fetchWithTimeout(url, fetchRequest, request.timeout) : fetch(url, fetchRequest)
if (!request.timeout) {
return fetch(url, fetchRequest);
}
return fetchWithTimeout(url, fetchRequest, request.timeout);
}
function fetchWithTimeout(url, options, timeoutMs) {
return console.log("fetchWithTimeout: timeoutMs: " + timeoutMs + ", url: " + url), new Promise(function(resolve, reject) {
console.log('fetchWithTimeout: timeoutMs: ' + timeoutMs + ', url: ' + url);
return new Promise(function (resolve, reject) {
var timeout = setTimeout(reject, timeoutMs);
options = options || {}, options.credentials = "same-origin", fetch(url, options).then(function(response) {
clearTimeout(timeout), console.log("fetchWithTimeout: succeeded connecting to url: " + url), resolve(response)
}, function(error) {
clearTimeout(timeout), console.log("fetchWithTimeout: timed out connecting to url: " + url), reject()
})
})
options = options || {};
options.credentials = 'same-origin';
fetch(url, options).then(function (response) {
clearTimeout(timeout);
console.log('fetchWithTimeout: succeeded connecting to url: ' + url);
resolve(response);
}, function (error) {
clearTimeout(timeout);
console.log('fetchWithTimeout: timed out connecting to url: ' + url);
reject();
});
});
}
function paramsToString(params) {
var values = [];
for (var key in params) {
var value = params[key];
null !== value && void 0 !== value && "" !== value && values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value))
if (value !== null && value !== undefined && value !== '') {
values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
}
}
return values.join("&")
return values.join('&');
}
function ajax(request) {
if (!request) throw new Error("Request cannot be null");
return request.headers = request.headers || {}, console.log("requesting url: " + request.url), getFetchPromise(request).then(function(response) {
return console.log("response status: " + response.status + ", url: " + request.url), response.status < 400 ? "json" === request.dataType || "application/json" === request.headers.accept ? response.json() : "text" === request.dataType || 0 === (response.headers.get("Content-Type") || "").toLowerCase().indexOf("text/") ? response.text() : response : Promise.reject(response)
}, function(err) {
throw console.log("request failed to url: " + request.url), err
})
if (!request) {
throw new Error("Request cannot be null");
}
request.headers = request.headers || {};
console.log('requesting url: ' + request.url);
return getFetchPromise(request).then(function (response) {
console.log('response status: ' + response.status + ', url: ' + request.url);
if (response.status < 400) {
if (request.dataType === 'json' || request.headers.accept === 'application/json') {
return response.json();
} else if (request.dataType === 'text' || (response.headers.get('Content-Type') || '').toLowerCase().indexOf('text/') === 0) {
return response.text();
} else {
return response;
}
} else {
return Promise.reject(response);
}
}, function (err) {
console.log('request failed to url: ' + request.url);
throw err;
});
}
return {
getFetchPromise: getFetchPromise,
ajax: ajax
}
};
});
+9 -7
View File
@@ -1,10 +1,12 @@
define(["multi-download"], function(multiDownload) {
"use strict";
define(['multi-download'], function (multiDownload) {
'use strict';
return {
download: function(items) {
multiDownload(items.map(function(item) {
return item.url
}))
download: function (items) {
multiDownload(items.map(function (item) {
return item.url;
}));
}
}
};
});
+8 -7
View File
@@ -1,11 +1,12 @@
define([], function() {
"use strict";
define([], function () {
'use strict';
return {
fileExists: function(path) {
return Promise.reject()
fileExists: function (path) {
return Promise.reject();
},
directoryExists: function(path) {
return Promise.reject()
directoryExists: function (path) {
return Promise.reject();
}
}
};
});
@@ -1,125 +1,348 @@
define(["require", "dom", "focusManager", "dialogHelper", "loading", "apphost", "inputManager", "layoutManager", "connectionManager", "appRouter", "globalize", "userSettings", "emby-checkbox", "emby-input", "paper-icon-button-light", "emby-select", "material-icons", "css!./../formdialog", "emby-button", "emby-linkbutton", "flexStyles"], function(require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) {
"use strict";
define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', 'inputManager', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'userSettings', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'emby-linkbutton', 'flexStyles'], function (require, dom, focusManager, dialogHelper, loading, appHost, inputManager, layoutManager, connectionManager, appRouter, globalize, userSettings) {
'use strict';
function onSubmit(e) {
return e.preventDefault(), !1
e.preventDefault();
return false;
}
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
var elem = context.querySelector(selector);
items.length ? elem.classList.remove("hide") : elem.classList.add("hide");
var html = "";
html += items.map(function(filter) {
var itemHtml = "",
checkedHtml = isCheckedFn(filter) ? " checked" : "";
return itemHtml += "<label>", itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>', itemHtml += "<span>" + filter.Name + "</span>", itemHtml += "</label>"
}).join(""), elem.querySelector(".filterOptions").innerHTML = html
if (items.length) {
elem.classList.remove('hide');
} else {
elem.classList.add('hide');
}
var html = '';
html += items.map(function (filter) {
var itemHtml = '';
var checkedHtml = isCheckedFn(filter) ? ' checked' : '';
itemHtml += '<label>';
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
itemHtml += '<span>' + filter.Name + '</span>';
itemHtml += '</label>';
return itemHtml;
}).join('');
elem.querySelector('.filterOptions').innerHTML = html;
}
function renderDynamicFilters(context, result, options) {
renderOptions(context, ".genreFilters", "chkGenreFilter", result.Genres, function(i) {
var delimeter = -1 === (options.settings.GenreIds || "").indexOf("|") ? "," : "|";
return -1 !== (delimeter + (options.settings.GenreIds || "") + delimeter).indexOf(delimeter + i.Id + delimeter)
})
// If there's a huge number of these they will be really show to render
//if (result.Tags) {
// result.Tags.length = Math.min(result.Tags.length, 50);
//}
renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) {
// Switching from | to ,
var delimeter = (options.settings.GenreIds || '').indexOf('|') === -1 ? ',' : '|';
return (delimeter + (options.settings.GenreIds || '') + delimeter).indexOf(delimeter + i.Id + delimeter) !== -1;
});
//renderOptions(context, '.officialRatingFilters', 'chkOfficialRatingFilter', result.OfficialRatings, function (i) {
// var delimeter = '|';
// return (delimeter + (query.OfficialRatings || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
//});
//renderOptions(context, '.tagFilters', 'chkTagFilter', result.Tags, function (i) {
// var delimeter = '|';
// return (delimeter + (query.Tags || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
//});
//renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) {
// var delimeter = ',';
// return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1;
//});
}
function loadDynamicFilters(context, options) {
var apiClient = connectionManager.getApiClient(options.serverId),
filterMenuOptions = Object.assign(options.filterMenuOptions, {
UserId: apiClient.getCurrentUserId(),
ParentId: options.parentId,
IncludeItemTypes: options.itemTypes.join(",")
});
apiClient.getFilters(filterMenuOptions).then(function(result) {
renderDynamicFilters(context, result, options)
}, function() {})
var apiClient = connectionManager.getApiClient(options.serverId);
var filterMenuOptions = Object.assign(options.filterMenuOptions, {
UserId: apiClient.getCurrentUserId(),
ParentId: options.parentId,
IncludeItemTypes: options.itemTypes.join(',')
});
apiClient.getFilters(filterMenuOptions).then(function (result) {
renderDynamicFilters(context, result, options);
}, function () {
// older server
});
}
function initEditor(context, settings) {
context.querySelector("form").addEventListener("submit", onSubmit);
var i, length, elems = context.querySelectorAll(".simpleFilter");
for (i = 0, length = elems.length; i < length; i++) "INPUT" === elems[i].tagName ? elems[i].checked = settings[elems[i].getAttribute("data-settingname")] || !1 : elems[i].querySelector("input").checked = settings[elems[i].getAttribute("data-settingname")] || !1;
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(",") : [];
for (elems = context.querySelectorAll(".chkVideoTypeFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked = -1 !== videoTypes.indexOf(elems[i].getAttribute("data-filter"));
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(",") : [];
for (elems = context.querySelectorAll(".chkSeriesStatus"), i = 0, length = elems.length; i < length; i++) elems[i].checked = -1 !== seriesStatuses.indexOf(elems[i].getAttribute("data-filter"));
context.querySelector(".basicFilterSection .viewSetting:not(.hide)") ? context.querySelector(".basicFilterSection").classList.remove("hide") : context.querySelector(".basicFilterSection").classList.add("hide"), context.querySelector(".featureSection .viewSetting:not(.hide)") ? context.querySelector(".featureSection").classList.remove("hide") : context.querySelector(".featureSection").classList.add("hide")
context.querySelector('form').addEventListener('submit', onSubmit);
var elems = context.querySelectorAll('.simpleFilter');
var i, length;
for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].tagName === 'INPUT') {
elems[i].checked = settings[elems[i].getAttribute('data-settingname')] || false;
} else {
elems[i].querySelector('input').checked = settings[elems[i].getAttribute('data-settingname')] || false;
}
}
var videoTypes = settings.VideoTypes ? settings.VideoTypes.split(',') : [];
elems = context.querySelectorAll('.chkVideoTypeFilter');
for (i = 0, length = elems.length; i < length; i++) {
elems[i].checked = videoTypes.indexOf(elems[i].getAttribute('data-filter')) !== -1;
}
var seriesStatuses = settings.SeriesStatus ? settings.SeriesStatus.split(',') : [];
elems = context.querySelectorAll('.chkSeriesStatus');
for (i = 0, length = elems.length; i < length; i++) {
elems[i].checked = seriesStatuses.indexOf(elems[i].getAttribute('data-filter')) !== -1;
}
if (context.querySelector('.basicFilterSection .viewSetting:not(.hide)')) {
context.querySelector('.basicFilterSection').classList.remove('hide');
} else {
context.querySelector('.basicFilterSection').classList.add('hide');
}
if (context.querySelector('.featureSection .viewSetting:not(.hide)')) {
context.querySelector('.featureSection').classList.remove('hide');
} else {
context.querySelector('.featureSection').classList.add('hide');
}
}
function saveValues(context, settings, settingsKey) {
var i, length, elems = context.querySelectorAll(".simpleFilter");
for (i = 0, length = elems.length; i < length; i++) "INPUT" === elems[i].tagName ? setBasicFilter(context, settingsKey + "-filter-" + elems[i].getAttribute("data-settingname"), elems[i]) : setBasicFilter(context, settingsKey + "-filter-" + elems[i].getAttribute("data-settingname"), elems[i].querySelector("input"));
var elems = context.querySelectorAll('.simpleFilter');
var i, length;
for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].tagName === 'INPUT') {
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i]);
} else {
setBasicFilter(context, settingsKey + '-filter-' + elems[i].getAttribute('data-settingname'), elems[i].querySelector('input'));
}
}
// Video type
var videoTypes = [];
for (elems = context.querySelectorAll(".chkVideoTypeFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked && videoTypes.push(elems[i].getAttribute("data-filter"));
userSettings.setFilter(settingsKey + "-filter-VideoTypes", videoTypes.join(","));
elems = context.querySelectorAll('.chkVideoTypeFilter');
for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].checked) {
videoTypes.push(elems[i].getAttribute('data-filter'));
}
}
userSettings.setFilter(settingsKey + '-filter-VideoTypes', videoTypes.join(','));
// Series status
var seriesStatuses = [];
for (elems = context.querySelectorAll(".chkSeriesStatus"), i = 0, length = elems.length; i < length; i++) elems[i].checked && seriesStatuses.push(elems[i].getAttribute("data-filter"));
elems = context.querySelectorAll('.chkSeriesStatus');
for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].checked) {
seriesStatuses.push(elems[i].getAttribute('data-filter'));
}
}
// Genres
var genres = [];
for (elems = context.querySelectorAll(".chkGenreFilter"), i = 0, length = elems.length; i < length; i++) elems[i].checked && genres.push(elems[i].getAttribute("data-filter"));
userSettings.setFilter(settingsKey + "-filter-GenreIds", genres.join(","))
elems = context.querySelectorAll('.chkGenreFilter');
for (i = 0, length = elems.length; i < length; i++) {
if (elems[i].checked) {
genres.push(elems[i].getAttribute('data-filter'));
}
}
userSettings.setFilter(settingsKey + '-filter-GenreIds', genres.join(','));
}
function setBasicFilter(context, key, elem) {
var value = elem.checked;
value = value || null, userSettings.setFilter(key, value)
value = value ? value : null;
userSettings.setFilter(key, value);
}
function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) {
var fn = on ? "on" : "off";
scrollHelper.centerFocus[fn](elem, horiz)
})
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function moveCheckboxFocus(elem, offset) {
for (var parent = dom.parentWithClass(elem, "checkboxList-verticalwrap"), elems = focusManager.getFocusableElements(parent), index = -1, i = 0, length = elems.length; i < length; i++)
var parent = dom.parentWithClass(elem, 'checkboxList-verticalwrap');
var elems = focusManager.getFocusableElements(parent);
var index = -1;
for (var i = 0, length = elems.length; i < length; i++) {
if (elems[i] === elem) {
index = i;
break
} index += offset, index = Math.min(elems.length - 1, index), index = Math.max(0, index);
break;
}
}
index += offset;
index = Math.min(elems.length - 1, index);
index = Math.max(0, index);
var newElem = elems[index];
newElem && focusManager.focus(newElem)
if (newElem) {
focusManager.focus(newElem);
}
}
function onInputCommand(e) {
switch (e.detail.command) {
case "left":
moveCheckboxFocus(e.target, -1), e.preventDefault();
case 'left':
moveCheckboxFocus(e.target, -1);
e.preventDefault();
break;
case 'right':
moveCheckboxFocus(e.target, 1);
e.preventDefault();
break;
default:
break;
case "right":
moveCheckboxFocus(e.target, 1), e.preventDefault()
}
}
function FilterMenu() {}
function FilterMenu() {
}
function bindCheckboxInput(context, on) {
for (var elems = context.querySelectorAll(".checkboxList-verticalwrap"), i = 0, length = elems.length; i < length; i++) on ? inputManager.on(elems[i], onInputCommand) : inputManager.off(elems[i], onInputCommand)
var elems = context.querySelectorAll('.checkboxList-verticalwrap');
for (var i = 0, length = elems.length; i < length; i++) {
if (on) {
inputManager.on(elems[i], onInputCommand);
} else {
inputManager.off(elems[i], onInputCommand);
}
}
}
return FilterMenu.prototype.show = function(options) {
return new Promise(function(resolve, reject) {
require(["text!./filtermenu.template.html"], function(template) {
FilterMenu.prototype.show = function (options) {
return new Promise(function (resolve, reject) {
require(['text!./filtermenu.template.html'], function (template) {
var dialogOptions = {
removeOnClose: !0,
scrollY: !1
removeOnClose: true,
scrollY: false
};
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small";
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog");
var html = "";
html += '<div class="formDialogHeader">', html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>', html += '<h3 class="formDialogHeaderTitle">${Filters}</h3>', html += "</div>", html += template, dlg.innerHTML = globalize.translateDocument(html, "sharedcomponents");
for (var settingElements = dlg.querySelectorAll(".viewSetting"), i = 0, length = settingElements.length; i < length; i++) - 1 === options.visibleSettings.indexOf(settingElements[i].getAttribute("data-settingname")) ? settingElements[i].classList.add("hide") : settingElements[i].classList.remove("hide");
initEditor(dlg, options.settings), loadDynamicFilters(dlg, options), bindCheckboxInput(dlg, !0), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg)
}), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0);
dlg.classList.add('formDialog');
var html = '';
html += '<div class="formDialogHeader">';
html += '<button is="paper-icon-button-light" class="btnCancel hide-mouse-idle-tv" tabindex="-1"><i class="md-icon">&#xE5C4;</i></button>';
html += '<h3 class="formDialogHeaderTitle">${Filters}</h3>';
html += '</div>';
html += template;
dlg.innerHTML = globalize.translateDocument(html, 'sharedcomponents');
var settingElements = dlg.querySelectorAll('.viewSetting');
for (var i = 0, length = settingElements.length; i < length; i++) {
if (options.visibleSettings.indexOf(settingElements[i].getAttribute('data-settingname')) === -1) {
settingElements[i].classList.add('hide');
} else {
settingElements[i].classList.remove('hide');
}
}
initEditor(dlg, options.settings);
loadDynamicFilters(dlg, options);
bindCheckboxInput(dlg, true);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
var submitted;
dlg.querySelector("form").addEventListener("change", function() {
submitted = !0
}, !0), dialogHelper.open(dlg).then(function() {
if (bindCheckboxInput(dlg, !1), layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted) return saveValues(dlg, options.settings, options.settingsKey), void resolve();
reject()
})
})
})
}, FilterMenu
dlg.querySelector('form').addEventListener('change', function () {
submitted = true;
//if (options.onChange) {
// saveValues(dlg, options.settings, options.settingsKey);
// options.onChange();
//}
}, true);
dialogHelper.open(dlg).then(function () {
bindCheckboxInput(dlg, false);
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (submitted) {
//if (!options.onChange) {
saveValues(dlg, options.settings, options.settingsKey);
resolve();
//}
return;
}
reject();
});
});
});
};
return FilterMenu;
});
+12 -35
View File
@@ -1,70 +1,47 @@
.flex {
display: -webkit-box;
display: -webkit-flex;
display: flex
display: flex;
}
.inline-flex {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex
display: inline-flex;
}
.flex-direction-column {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column
flex-direction: column;
}
.flex-direction-row {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row
flex-direction: row;
}
.flex-grow {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1
flex-grow: 1;
}
.flex-shrink-zero {
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.align-items-center {
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center
align-items: center;
}
.align-items-flex-start {
-webkit-box-align: start;
-webkit-align-items: flex-start;
align-items: flex-start
align-items: flex-start;
}
.justify-content-center {
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center
justify-content: center;
}
.justify-content-flex-end {
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
justify-content: flex-end
justify-content: flex-end;
}
.flex-wrap-wrap {
-webkit-flex-wrap: wrap;
flex-wrap: wrap
flex-wrap: wrap;
}
.align-self-flex-end {
-webkit-align-self: flex-end;
align-self: flex-end
align-self: flex-end;
}
File diff suppressed because one or more lines are too long
+434 -139
View File
@@ -1,249 +1,544 @@
define(["dom"], function(dom) {
"use strict";
define(['dom'], function (dom) {
'use strict';
var scopes = [];
function pushScope(elem) {
scopes.push(elem)
scopes.push(elem);
}
function popScope(elem) {
scopes.length && (scopes.length -= 1)
}
function autoFocus(view, defaultToFirst, findAutoFocusElement) {
var element;
return !1 !== findAutoFocusElement && (element = view.querySelector("*[autofocus]")) ? (focus(element), element) : !1 !== defaultToFirst && (element = getFocusableElements(view, 1, "noautofocus")[0]) ? (focus(element), element) : null
}
function focus(element) {
try {
element.focus({
preventScroll: !0
})
} catch (err) {
console.log("Error in focusManager.autoFocus: " + err)
if (scopes.length) {
scopes.length -= 1;
}
}
function autoFocus(view, defaultToFirst, findAutoFocusElement) {
var element;
if (findAutoFocusElement !== false) {
element = view.querySelector('*[autofocus]');
if (element) {
focus(element);
return element;
}
}
if (defaultToFirst !== false) {
element = getFocusableElements(view, 1, 'noautofocus')[0];
if (element) {
focus(element);
return element;
}
}
return null;
}
function focus(element) {
try {
element.focus({
preventScroll: true
});
} catch (err) {
console.log('Error in focusManager.autoFocus: ' + err);
}
}
var focusableTagNames = ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'];
var focusableContainerTagNames = ['BODY', 'DIALOG'];
var focusableQuery = focusableTagNames.map(function (t) {
if (t === 'INPUT') {
t += ':not([type="range"]):not([type="file"])';
}
return t + ':not([tabindex="-1"]):not(:disabled)';
}).join(',') + ',.focusable';
function isFocusable(elem) {
return -1 !== focusableTagNames.indexOf(elem.tagName) || !(!elem.classList || !elem.classList.contains("focusable"))
if (focusableTagNames.indexOf(elem.tagName) !== -1) {
return true;
}
if (elem.classList && elem.classList.contains('focusable')) {
return true;
}
return false;
}
function normalizeFocusable(elem, originalElement) {
if (elem) {
var tagName = elem.tagName;
tagName && "HTML" !== tagName && "BODY" !== tagName || (elem = originalElement)
if (!tagName || tagName === 'HTML' || tagName === 'BODY') {
elem = originalElement;
}
}
return elem
return elem;
}
function focusableParent(elem) {
for (var originalElement = elem; !isFocusable(elem);) {
var originalElement = elem;
while (!isFocusable(elem)) {
var parent = elem.parentNode;
if (!parent) return normalizeFocusable(elem, originalElement);
elem = parent
if (!parent) {
return normalizeFocusable(elem, originalElement);
}
elem = parent;
}
return normalizeFocusable(elem, originalElement)
return normalizeFocusable(elem, originalElement);
}
// Determines if a focusable element can be focused at a given point in time
function isCurrentlyFocusableInternal(elem) {
return null !== elem.offsetParent
// http://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom
if (elem.offsetParent === null) {
return false;
}
return true;
}
// Determines if a focusable element can be focused at a given point in time
function isCurrentlyFocusable(elem) {
if (elem.disabled) return !1;
if ("-1" === elem.getAttribute("tabindex")) return !1;
if ("INPUT" === elem.tagName) {
var type = elem.type;
if ("range" === type) return !1;
if ("file" === type) return !1
if (elem.disabled) {
return false;
}
return isCurrentlyFocusableInternal(elem)
if (elem.getAttribute('tabindex') === "-1") {
return false;
}
if (elem.tagName === 'INPUT') {
var type = elem.type;
if (type === 'range') {
return false;
}
if (type === 'file') {
return false;
}
}
return isCurrentlyFocusableInternal(elem);
}
function getDefaultScope() {
return scopes[0] || document.body
return scopes[0] || document.body;
}
function getFocusableElements(parent, limit, excludeClass) {
for (var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery), focusableElements = [], i = 0, length = elems.length; i < length; i++) {
var elems = (parent || getDefaultScope()).querySelectorAll(focusableQuery);
var focusableElements = [];
for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[i];
if ((!excludeClass || !elem.classList.contains(excludeClass)) && (isCurrentlyFocusableInternal(elem) && (focusableElements.push(elem), limit && focusableElements.length >= limit))) break
if (excludeClass && elem.classList.contains(excludeClass)) {
continue;
}
if (isCurrentlyFocusableInternal(elem)) {
focusableElements.push(elem);
if (limit && focusableElements.length >= limit) {
break;
}
}
}
return focusableElements
return focusableElements;
}
function isFocusContainer(elem, direction) {
if (-1 !== focusableContainerTagNames.indexOf(elem.tagName)) return !0;
var classList = elem.classList;
if (classList.contains("focuscontainer")) return !0;
if (0 === direction) {
if (classList.contains("focuscontainer-x")) return !0;
if (classList.contains("focuscontainer-left")) return !0
} else if (1 === direction) {
if (classList.contains("focuscontainer-x")) return !0;
if (classList.contains("focuscontainer-right")) return !0
} else if (2 === direction) {
if (classList.contains("focuscontainer-y")) return !0
} else if (3 === direction) {
if (classList.contains("focuscontainer-y")) return !0;
if (classList.contains("focuscontainer-down")) return !0
if (focusableContainerTagNames.indexOf(elem.tagName) !== -1) {
return true;
}
return !1
var classList = elem.classList;
if (classList.contains('focuscontainer')) {
return true;
}
if (direction === 0) {
if (classList.contains('focuscontainer-x')) {
return true;
}
if (classList.contains('focuscontainer-left')) {
return true;
}
}
else if (direction === 1) {
if (classList.contains('focuscontainer-x')) {
return true;
}
if (classList.contains('focuscontainer-right')) {
return true;
}
}
else if (direction === 2) {
if (classList.contains('focuscontainer-y')) {
return true;
}
}
else if (direction === 3) {
if (classList.contains('focuscontainer-y')) {
return true;
}
if (classList.contains('focuscontainer-down')) {
return true;
}
}
return false;
}
function getFocusContainer(elem, direction) {
for (; !isFocusContainer(elem, direction);)
if (!(elem = elem.parentNode)) return getDefaultScope();
return elem
while (!isFocusContainer(elem, direction)) {
elem = elem.parentNode;
if (!elem) {
return getDefaultScope();
}
}
return elem;
}
function getOffset(elem) {
var box;
if (box = elem.getBoundingClientRect ? elem.getBoundingClientRect() : {
// Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) {
box = elem.getBoundingClientRect();
} else {
box = {
top: 0,
left: 0,
width: 0,
height: 0
}, null === box.right) {
box = {
};
}
if (box.right === null) {
// Create a new object because some browsers will throw an error when trying to set data onto the Rect object
var newBox = {
top: box.top,
left: box.left,
width: box.width,
height: box.height
}, box.right = box.left + box.width, box.bottom = box.top + box.height
};
box = newBox;
box.right = box.left + box.width;
box.bottom = box.top + box.height;
}
return box
return box;
}
function nav(activeElement, direction, container, focusableElements) {
if (activeElement = activeElement || document.activeElement, activeElement && (activeElement = focusableParent(activeElement)), container = container || (activeElement ? getFocusContainer(activeElement, direction) : getDefaultScope()), !activeElement) return void autoFocus(container, !0, !1);
for (var nearestElement, focusableContainer = dom.parentWithClass(activeElement, "focusable"), rect = getOffset(activeElement), point1x = parseFloat(rect.left) || 0, point1y = parseFloat(rect.top) || 0, point2x = parseFloat(point1x + rect.width - 1) || point1x, point2y = parseFloat(point1y + rect.height - 1) || point1y, sourceMidX = (Math.min, Math.max, rect.left + rect.width / 2), sourceMidY = rect.top + rect.height / 2, focusable = focusableElements || container.querySelectorAll(focusableQuery), minDistance = 1 / 0, i = 0, length = focusable.length; i < length; i++) {
activeElement = activeElement || document.activeElement;
if (activeElement) {
activeElement = focusableParent(activeElement);
}
container = container || (activeElement ? getFocusContainer(activeElement, direction) : getDefaultScope());
if (!activeElement) {
autoFocus(container, true, false);
return;
}
var focusableContainer = dom.parentWithClass(activeElement, 'focusable');
var rect = getOffset(activeElement);
// Get elements and work out x/y points
var cache = [],
point1x = parseFloat(rect.left) || 0,
point1y = parseFloat(rect.top) || 0,
point2x = parseFloat(point1x + rect.width - 1) || point1x,
point2y = parseFloat(point1y + rect.height - 1) || point1y,
// Shortcuts to help with compression
min = Math.min,
max = Math.max;
var sourceMidX = rect.left + (rect.width / 2);
var sourceMidY = rect.top + (rect.height / 2);
var focusable = focusableElements || container.querySelectorAll(focusableQuery);
var maxDistance = Infinity;
var minDistance = maxDistance;
var nearestElement;
for (var i = 0, length = focusable.length; i < length; i++) {
var curr = focusable[i];
if (curr !== activeElement && curr !== focusableContainer) {
var elementRect = getOffset(curr);
if (elementRect.width || elementRect.height) {
switch (direction) {
case 0:
if (elementRect.left >= rect.left) continue;
if (elementRect.right === rect.right) continue;
break;
case 1:
if (elementRect.right <= rect.right) continue;
if (elementRect.left === rect.left) continue;
break;
case 2:
if (elementRect.top >= rect.top) continue;
if (elementRect.bottom >= rect.bottom) continue;
break;
case 3:
if (elementRect.bottom <= rect.bottom) continue;
if (elementRect.top <= rect.top) continue
if (curr === activeElement) {
continue;
}
// Don't refocus into the same container
if (curr === focusableContainer) {
continue;
}
//if (!isCurrentlyFocusableInternal(curr)) {
// continue;
//}
var elementRect = getOffset(curr);
// not currently visible
if (!elementRect.width && !elementRect.height) {
continue;
}
switch (direction) {
case 0:
// left
if (elementRect.left >= rect.left) {
continue;
}
var distX, distY, x = elementRect.left,
y = elementRect.top,
x2 = x + elementRect.width - 1,
y2 = y + elementRect.height - 1,
intersectX = intersects(point1x, point2x, x, x2),
intersectY = intersects(point1y, point2y, y, y2),
midX = elementRect.left + elementRect.width / 2,
midY = elementRect.top + elementRect.height / 2;
switch (direction) {
case 0:
distX = Math.abs(point1x - Math.min(point1x, x2)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
break;
case 1:
distX = Math.abs(point2x - Math.max(point2x, x)), distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
break;
case 2:
distY = Math.abs(point1y - Math.min(point1y, y2)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
break;
case 3:
distY = Math.abs(point2y - Math.max(point2y, y)), distX = intersectX ? 0 : Math.abs(sourceMidX - midX)
if (elementRect.right === rect.right) {
continue;
}
var dist = Math.sqrt(distX * distX + distY * distY);
dist < minDistance && (nearestElement = curr, minDistance = dist)
}
break;
case 1:
// right
if (elementRect.right <= rect.right) {
continue;
}
if (elementRect.left === rect.left) {
continue;
}
break;
case 2:
// up
if (elementRect.top >= rect.top) {
continue;
}
if (elementRect.bottom >= rect.bottom) {
continue;
}
break;
case 3:
// down
if (elementRect.bottom <= rect.bottom) {
continue;
}
if (elementRect.top <= rect.top) {
continue;
}
break;
default:
break;
}
var x = elementRect.left,
y = elementRect.top,
x2 = x + elementRect.width - 1,
y2 = y + elementRect.height - 1;
var intersectX = intersects(point1x, point2x, x, x2);
var intersectY = intersects(point1y, point2y, y, y2);
var midX = elementRect.left + (elementRect.width / 2);
var midY = elementRect.top + (elementRect.height / 2);
var distX;
var distY;
switch (direction) {
case 0:
// left
distX = Math.abs(point1x - Math.min(point1x, x2));
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
break;
case 1:
// right
distX = Math.abs(point2x - Math.max(point2x, x));
distY = intersectY ? 0 : Math.abs(sourceMidY - midY);
break;
case 2:
// up
distY = Math.abs(point1y - Math.min(point1y, y2));
distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
break;
case 3:
// down
distY = Math.abs(point2y - Math.max(point2y, y));
distX = intersectX ? 0 : Math.abs(sourceMidX - midX);
break;
default:
break;
}
var dist = Math.sqrt(distX * distX + distY * distY);
if (dist < minDistance) {
nearestElement = curr;
minDistance = dist;
}
}
if (nearestElement) {
// See if there's a focusable container, and if so, send the focus command to that
if (activeElement) {
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, "focusable");
nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement && focusableContainer !== nearestElementFocusableParent && (nearestElement = nearestElementFocusableParent)
var nearestElementFocusableParent = dom.parentWithClass(nearestElement, 'focusable');
if (nearestElementFocusableParent && nearestElementFocusableParent !== nearestElement) {
if (focusableContainer !== nearestElementFocusableParent) {
nearestElement = nearestElementFocusableParent;
}
}
}
focus(nearestElement)
focus(nearestElement);
}
}
function intersectsInternal(a1, a2, b1, b2) {
return b1 >= a1 && b1 <= a2 || b2 >= a1 && b2 <= a2
return (b1 >= a1 && b1 <= a2) || (b2 >= a1 && b2 <= a2);
}
function intersects(a1, a2, b1, b2) {
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2)
return intersectsInternal(a1, a2, b1, b2) || intersectsInternal(b1, b2, a1, a2);
}
function sendText(text) {
document.activeElement.value = text
var elem = document.activeElement;
elem.value = text;
}
function focusFirst(container, focusableSelector) {
for (var elems = container.querySelectorAll(focusableSelector), i = 0, length = elems.length; i < length; i++) {
var elems = container.querySelectorAll(focusableSelector);
for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) {
focus(elem);
break
break;
}
}
}
function focusLast(container, focusableSelector) {
for (var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse(), i = 0, length = elems.length; i < length; i++) {
var elems = [].slice.call(container.querySelectorAll(focusableSelector), 0).reverse();
for (var i = 0, length = elems.length; i < length; i++) {
var elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) {
focus(elem);
break
break;
}
}
}
function moveFocus(sourceElement, container, focusableSelector, offset) {
var i, length, elem, elems = container.querySelectorAll(focusableSelector),
list = [];
for (i = 0, length = elems.length; i < length; i++) elem = elems[i], isCurrentlyFocusableInternal(elem) && list.push(elem);
var elems = container.querySelectorAll(focusableSelector);
var list = [];
var i, length, elem;
for (i = 0, length = elems.length; i < length; i++) {
elem = elems[i];
if (isCurrentlyFocusableInternal(elem)) {
list.push(elem);
}
}
var currentIndex = -1;
for (i = 0, length = list.length; i < length; i++)
if (elem = list[i], sourceElement === elem || elem.contains(sourceElement)) {
for (i = 0, length = list.length; i < length; i++) {
elem = list[i];
if (sourceElement === elem || elem.contains(sourceElement)) {
currentIndex = i;
break
} if (-1 !== currentIndex) {
var newIndex = currentIndex + offset;
newIndex = Math.max(0, newIndex), newIndex = Math.min(newIndex, list.length - 1);
var newElem = list[newIndex];
newElem && focus(newElem)
break;
}
}
if (currentIndex === -1) {
return;
}
var newIndex = currentIndex + offset;
newIndex = Math.max(0, newIndex);
newIndex = Math.min(newIndex, list.length - 1);
var newElem = list[newIndex];
if (newElem) {
focus(newElem);
}
}
var scopes = [],
focusableTagNames = ["INPUT", "TEXTAREA", "SELECT", "BUTTON", "A"],
focusableContainerTagNames = ["BODY", "DIALOG"],
focusableQuery = focusableTagNames.map(function(t) {
return "INPUT" === t && (t += ':not([type="range"]):not([type="file"])'), t + ':not([tabindex="-1"]):not(:disabled)'
}).join(",") + ",.focusable";
return {
autoFocus: autoFocus,
focus: focus,
focusableParent: focusableParent,
getFocusableElements: getFocusableElements,
moveLeft: function(sourceElement, options) {
nav(sourceElement, 0, options ? options.container : null, options ? options.focusableElements : null)
moveLeft: function (sourceElement, options) {
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 0, container, focusableElements);
},
moveRight: function(sourceElement, options) {
nav(sourceElement, 1, options ? options.container : null, options ? options.focusableElements : null)
moveRight: function (sourceElement, options) {
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 1, container, focusableElements);
},
moveUp: function(sourceElement, options) {
nav(sourceElement, 2, options ? options.container : null, options ? options.focusableElements : null)
moveUp: function (sourceElement, options) {
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 2, container, focusableElements);
},
moveDown: function(sourceElement, options) {
nav(sourceElement, 3, options ? options.container : null, options ? options.focusableElements : null)
moveDown: function (sourceElement, options) {
var container = options ? options.container : null;
var focusableElements = options ? options.focusableElements : null;
nav(sourceElement, 3, container, focusableElements);
},
sendText: sendText,
isCurrentlyFocusable: isCurrentlyFocusable,
@@ -252,5 +547,5 @@ define(["dom"], function(dom) {
focusFirst: focusFirst,
focusLast: focusLast,
moveFocus: moveFocus
}
};
});
+15 -17
View File
@@ -1,39 +1,37 @@
h1,
h2,
h3 {
font-weight: 500
html {
font-family: -apple-system, "Helvetica", system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif;
}
html {
font-family: -apple-system, Helvetica, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", 'Open Sans', sans-serif;
font-size: 93%;
-webkit-text-size-adjust: 100%;
-moz-text-size-adjust: 100%;
text-size-adjust: 100%
text-size-adjust: 100%;
}
h1,
h2,
h3 {
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", 'Open Sans', sans-serif
h1, h2, h3 {
/* For better bolding, since Helvetica does not support 500 weight, and 600 is too thick */
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", 'Open Sans', sans-serif;
}
h1 {
font-size: 1.8em
font-weight: 500;
font-size: 1.8em;
}
h2 {
font-size: 1.5em
font-weight: 500;
font-size: 1.5em;
}
h3 {
font-size: 1.17em
font-weight: 500;
font-size: 1.17em;
}
.layout-tv {
font-size: 2.5vh
font-size: 2.5vh;
}
.layout-mobile {
font-size: 90%
}
font-size: 90%;
}
+14 -15
View File
@@ -1,33 +1,32 @@
h1,
h2,
h3 {
font-weight: 500
}
h1 {
font-size: 1.8em
font-weight: 500;
font-size: 1.8em;
}
.layout-desktop h1 {
font-size: 2em
font-size: 2em;
}
h2 {
font-size: 1.5em
font-weight: 500;
font-size: 1.5em;
}
h3 {
font-size: 1.17em
font-weight: 500;
font-size: 1.17em;
}
@media all and (min-height:720px) {
@media all and (min-height: 720px) {
html {
font-size: 20px
font-size: 20px;
}
}
@media all and (min-height:1000px) {
/* This is supposed to be 1080p, but had to reduce the min height to account for possible browser chrome */
@media all and (min-height: 1000px) {
html {
font-size: 27px
font-size: 27px;
}
}
}
@@ -2,12 +2,12 @@
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'), local('MaterialIcons-Regular'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff) format('woff')
src: local('Material Icons'), local('MaterialIcons-Regular'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2) format('woff2'), url(flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff) format('woff');
}
.md-icon {
font-family: 'Material Icons';
font-weight: 400;
font-weight: normal;
font-style: normal;
letter-spacing: normal;
text-transform: none;
@@ -15,12 +15,11 @@
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-webkit-font-feature-settings: "liga"1;
-moz-font-feature-settings: "liga"1;
font-feature-settings: "liga"1;
font-feature-settings: "liga" 1;
line-height: 1;
overflow: hidden;
vertical-align: middle
}
vertical-align: middle;
}
+26 -56
View File
@@ -1,145 +1,115 @@
.formDialog,
.formDialogHeader {
display: -webkit-box;
display: -webkit-flex
}
.formDialog,
.formDialogFooter-vertical {
-webkit-box-orient: vertical;
-webkit-box-direction: normal
}
.formDialog {
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
position: relative
position: relative;
}
.formDialogHeader {
padding: 1em .5em;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.formDialogHeaderTitle {
margin-left: .25em;
/* In case of h1, h2, h3 */
margin-top: 0;
margin-bottom: 0
margin-bottom: 0;
}
.formDialogContent:not(.no-grow) {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1
flex-grow: 1;
}
.dialogContentInner {
padding: .5em 1em 20em
padding: .5em 1em 20em 1em;
}
.dialogContentInner-mini {
padding-bottom: 10em
padding-bottom: 10em;
}
.dialog-content-centered {
margin: 0 auto;
max-width: 53em
max-width: 53em;
}
.dialogContentTitle {
margin-top: 1em
margin-top: 1em;
}
.formDialogFooter {
bottom: 0;
left: 0;
right: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex;
position: absolute;
padding: 1.25em 1em;
/* Without this emby-checkbox is able to appear on top */
z-index: 1;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-flex-wrap: wrap;
flex-wrap: wrap
flex-wrap: wrap;
}
.formDialogFooter-flex {
position: static;
width: 100%
width: 100%;
}
.formDialogFooter-vertical {
padding-bottom: 1.5em;
-webkit-flex-direction: column;
flex-direction: column;
width: 80% !important;
padding-top: .5em
padding-top: .5em;
}
.formDialogFooterItem {
margin: .5em !important;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1;
text-align: center;
-webkit-flex-basis: 0;
flex-basis: 0
flex-basis: 0;
}
.formDialogFooterItem-vertical {
max-width: none !important;
width: 100%;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
margin: 1em !important
margin: 1em !important;
}
.formDialogFooterItem-nomarginbottom {
margin-bottom: 0 !important
margin-bottom: 0 !important;
}
.formDialogFooterItem-autosize {
-webkit-flex-basis: initial;
flex-basis: initial;
-webkit-box-flex: initial;
-webkit-flex-grow: initial;
flex-grow: initial;
padding-left: 2em;
padding-right: 2em
padding-right: 2em;
}
@media all and (min-width:50em) {
@media all and (min-width: 50em) {
.formDialogFooterItem {
max-width: 80%
max-width: 80%;
}
.dialogContentInner {
padding-left: 1.5em;
padding-right: 1.5em
padding-right: 1.5em;
}
}
@media all and (min-width:80em) {
@media all and (min-width: 80em) {
.formDialogFooterItem {
max-width: 70%
max-width: 70%;
}
.dialogContentInner {
padding-left: 2em;
padding-right: 2em
padding-right: 2em;
}
}
}
@@ -1,12 +1,26 @@
define(["dom", "fullscreenManager"], function(dom, fullscreenManager) {
"use strict";
define(['dom', 'fullscreenManager'], function (dom, fullscreenManager) {
'use strict';
function isTargetValid(target) {
return !dom.parentWithTag(target, ["BUTTON", "INPUT", "TEXTAREA"])
if (dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA'])) {
return false;
}
return true;
}
dom.addEventListener(window, "dblclick", function(e) {
isTargetValid(e.target) && (fullscreenManager.isFullScreen() ? fullscreenManager.exitFullscreen() : fullscreenManager.requestFullscreen())
dom.addEventListener(window, 'dblclick', function (e) {
if (isTargetValid(e.target)) {
if (fullscreenManager.isFullScreen()) {
fullscreenManager.exitFullscreen();
} else {
fullscreenManager.requestFullscreen();
}
}
}, {
passive: !0
})
passive: true
});
});
@@ -1,24 +1,74 @@
define(["events", "dom"], function(events, dom) {
"use strict";
define(['events', 'dom'], function (events, dom) {
'use strict';
function fullscreenManager() {}
function fullscreenManager() {
}
fullscreenManager.prototype.requestFullscreen = function (element) {
element = element || document.documentElement;
if (element.requestFullscreen) {
element.requestFullscreen();
return;
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
return;
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
return;
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
return;
}
// Hack - This is only available for video elements in ios safari
if (element.tagName !== 'VIDEO') {
element = document.querySelector('video') || element;
}
if (element.webkitEnterFullscreen) {
element.webkitEnterFullscreen();
}
};
fullscreenManager.prototype.exitFullscreen = function () {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.webkitCancelFullscreen) {
document.webkitCancelFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
};
fullscreenManager.prototype.isFullScreen = function () {
return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false;
};
var manager = new fullscreenManager();
function onFullScreenChange() {
events.trigger(manager, "fullscreenchange")
events.trigger(manager, 'fullscreenchange');
}
fullscreenManager.prototype.requestFullscreen = function(element) {
return element = element || document.documentElement, element.requestFullscreen ? void element.requestFullscreen() : element.mozRequestFullScreen ? void element.mozRequestFullScreen() : element.webkitRequestFullscreen ? void element.webkitRequestFullscreen() : element.msRequestFullscreen ? void element.msRequestFullscreen() : ("VIDEO" !== element.tagName && (element = document.querySelector("video") || element), void(element.webkitEnterFullscreen && element.webkitEnterFullscreen()))
}, fullscreenManager.prototype.exitFullscreen = function() {
document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen ? document.webkitExitFullscreen() : document.webkitCancelFullscreen ? document.webkitCancelFullscreen() : document.msExitFullscreen && document.msExitFullscreen()
}, fullscreenManager.prototype.isFullScreen = function() {
return !!(document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement)
};
var manager = new fullscreenManager;
return dom.addEventListener(document, "fullscreenchange", onFullScreenChange, {
passive: !0
}), dom.addEventListener(document, "webkitfullscreenchange", onFullScreenChange, {
passive: !0
}), dom.addEventListener(document, "mozfullscreenchange", onFullScreenChange, {
passive: !0
}), manager
dom.addEventListener(document, 'fullscreenchange', onFullScreenChange, {
passive: true
});
dom.addEventListener(document, 'webkitfullscreenchange', onFullScreenChange, {
passive: true
});
dom.addEventListener(document, 'mozfullscreenchange', onFullScreenChange, {
passive: true
});
return manager;
});
+236 -76
View File
@@ -1,127 +1,287 @@
define(["connectionManager", "userSettings", "events"], function(connectionManager, userSettings, events) {
"use strict";
define(['connectionManager', 'userSettings', 'events'], function (connectionManager, userSettings, events) {
'use strict';
var allTranslations = {};
var currentCulture;
var currentDateTimeCulture;
function getCurrentLocale() {
return currentCulture
return currentCulture;
}
function getCurrentDateTimeLocale() {
return currentDateTimeCulture
return currentDateTimeCulture;
}
function getDefaultLanguage() {
var culture = document.documentElement.getAttribute("data-culture");
return culture || (navigator.language ? navigator.language : navigator.userLanguage ? navigator.userLanguage : navigator.languages && navigator.languages.length ? navigator.languages[0] : "en-us")
var culture = document.documentElement.getAttribute('data-culture');
if (culture) {
return culture;
}
if (navigator.language) {
return navigator.language;
}
if (navigator.userLanguage) {
return navigator.userLanguage;
}
if (navigator.languages && navigator.languages.length) {
return navigator.languages[0];
}
return 'en-us';
}
function updateCurrentCulture() {
var culture;
try {
culture = userSettings.language()
} catch (err) {}
culture = culture || getDefaultLanguage(), currentCulture = normalizeLocaleName(culture);
culture = userSettings.language();
} catch (err) {
}
culture = culture || getDefaultLanguage();
currentCulture = normalizeLocaleName(culture);
var dateTimeCulture;
try {
dateTimeCulture = userSettings.dateTimeLocale()
} catch (err) {}
currentDateTimeCulture = dateTimeCulture ? normalizeLocaleName(dateTimeCulture) : currentCulture, ensureTranslations(currentCulture)
dateTimeCulture = userSettings.dateTimeLocale();
} catch (err) {
}
if (dateTimeCulture) {
currentDateTimeCulture = normalizeLocaleName(dateTimeCulture);
}
else {
currentDateTimeCulture = currentCulture;
}
ensureTranslations(currentCulture);
}
function ensureTranslations(culture) {
for (var i in allTranslations) ensureTranslation(allTranslations[i], culture)
}
function ensureTranslation(translationInfo, culture) {
return translationInfo.dictionaries[culture] ? Promise.resolve() : loadTranslation(translationInfo.translations, culture).then(function(dictionary) {
translationInfo.dictionaries[culture] = dictionary
})
}
function normalizeLocaleName(culture) {
culture = culture.replace("_", "-");
var parts = culture.split("-");
2 === parts.length && parts[0].toLowerCase() === parts[1].toLowerCase() && (culture = parts[0].toLowerCase());
var lower = culture.toLowerCase();
return "ca-es" === lower ? "ca" : "sv-se" === lower ? "sv" : lower
}
function getDictionary(module) {
module || (module = defaultModule());
var translations = allTranslations[module];
return translations ? translations.dictionaries[getCurrentLocale()] : {}
}
function register(options) {
allTranslations[options.name] = {
translations: options.strings || options.translations,
dictionaries: {}
for (var i in allTranslations) {
ensureTranslation(allTranslations[i], culture);
}
}
function loadStrings(options) {
var locale = getCurrentLocale();
return "string" == typeof options ? ensureTranslation(allTranslations[options], locale) : (register(options), ensureTranslation(allTranslations[options.name], locale))
function ensureTranslation(translationInfo, culture) {
if (translationInfo.dictionaries[culture]) {
return Promise.resolve();
}
return loadTranslation(translationInfo.translations, culture).then(function (dictionary) {
translationInfo.dictionaries[culture] = dictionary;
});
}
function normalizeLocaleName(culture) {
culture = culture.replace('_', '-');
// If it's de-DE, convert to just de
var parts = culture.split('-');
if (parts.length === 2) {
if (parts[0].toLowerCase() === parts[1].toLowerCase()) {
culture = parts[0].toLowerCase();
}
}
var lower = culture.toLowerCase();
if (lower === 'ca-es') {
return 'ca';
}
// normalize Swedish
if (lower === 'sv-se') {
return 'sv';
}
return lower;
}
function getDictionary(module) {
if (!module) {
module = defaultModule();
}
var translations = allTranslations[module];
if (!translations) {
return {};
}
return translations.dictionaries[getCurrentLocale()];
}
function register(options) {
allTranslations[options.name] = {
translations: options.strings || options.translations,
dictionaries: {}
};
}
function loadStrings(options) {
var locale = getCurrentLocale();
if (typeof options === 'string') {
return ensureTranslation(allTranslations[options], locale);
} else {
register(options);
return ensureTranslation(allTranslations[options.name], locale);
}
}
var cacheParam = new Date().getTime();
function loadTranslation(translations, lang) {
lang = normalizeLocaleName(lang);
var filtered = translations.filter(function(t) {
return normalizeLocaleName(t.lang) === lang
var filtered = translations.filter(function (t) {
return normalizeLocaleName(t.lang) === lang;
});
return filtered.length || (filtered = translations.filter(function(t) {
return "en-us" === normalizeLocaleName(t.lang)
})), new Promise(function(resolve, reject) {
if (!filtered.length) return void resolve();
if (!filtered.length) {
filtered = translations.filter(function (t) {
return normalizeLocaleName(t.lang) === 'en-us';
});
}
return new Promise(function (resolve, reject) {
if (!filtered.length) {
resolve();
return;
}
var url = filtered[0].path;
url += -1 === url.indexOf("?") ? "?" : "&", url += "v=" + cacheParam;
var xhr = new XMLHttpRequest;
xhr.open("GET", url, !0), xhr.onload = function(e) {
resolve(this.status < 400 ? JSON.parse(this.response) : {})
}, xhr.onerror = function() {
resolve({})
}, xhr.send()
})
url += url.indexOf('?') === -1 ? '?' : '&';
url += 'v=' + cacheParam;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
if (this.status < 400) {
resolve(JSON.parse(this.response));
} else {
resolve({});
}
};
xhr.onerror = function () {
resolve({});
};
xhr.send();
});
}
function translateKey(key) {
var module, parts = key.split("#");
return parts.length > 1 && (module = parts[0], key = parts[1]), translateKeyFromModule(key, module)
var parts = key.split('#');
var module;
if (parts.length > 1) {
module = parts[0];
key = parts[1];
}
return translateKeyFromModule(key, module);
}
function translateKeyFromModule(key, module) {
var dictionary = getDictionary(module);
return dictionary ? dictionary[key] || key : key
if (!dictionary) {
return key;
}
return dictionary[key] || key;
}
function replaceAll(str, find, replace) {
return str.split(find).join(replace)
return str.split(find).join(replace);
}
function translate(key) {
for (var val = translateKey(key), i = 1; i < arguments.length; i++) val = replaceAll(val, "{" + (i - 1) + "}", arguments[i]);
return val
var val = translateKey(key);
for (var i = 1; i < arguments.length; i++) {
val = replaceAll(val, '{' + (i - 1) + '}', arguments[i]);
}
return val;
}
function translateHtml(html, module) {
if (module || (module = defaultModule()), !module) throw new Error("module cannot be null or empty");
var startIndex = html.indexOf("${");
if (-1 === startIndex) return html;
if (!module) {
module = defaultModule();
}
if (!module) {
throw new Error('module cannot be null or empty');
}
var startIndex = html.indexOf('${');
if (startIndex === -1) {
return html;
}
startIndex += 2;
var endIndex = html.indexOf("}", startIndex);
if (-1 === endIndex) return html;
var key = html.substring(startIndex, endIndex),
val = translateKeyFromModule(key, module);
return html = html.replace("${" + key + "}", val), translateHtml(html, module)
var endIndex = html.indexOf('}', startIndex);
if (endIndex === -1) {
return html;
}
var key = html.substring(startIndex, endIndex);
var val = translateKeyFromModule(key, module);
html = html.replace('${' + key + '}', val);
return translateHtml(html, module);
}
var _defaultModule;
function defaultModule(val) {
return val && (_defaultModule = val), _defaultModule
if (val) {
_defaultModule = val;
}
return _defaultModule;
}
var currentCulture, currentDateTimeCulture, _defaultModule, allTranslations = {},
cacheParam = (new Date).getTime();
return updateCurrentCulture(), events.on(connectionManager, "localusersignedin", updateCurrentCulture), events.on(userSettings, "change", function(e, name) {
"language" !== name && "datetimelocale" !== name || updateCurrentCulture()
}), {
updateCurrentCulture();
events.on(connectionManager, 'localusersignedin', updateCurrentCulture);
events.on(userSettings, 'change', function (e, name) {
if (name === 'language' || name === 'datetimelocale') {
updateCurrentCulture();
}
});
return {
getString: translate,
translate: translate,
translateDocument: translateHtml,
@@ -131,5 +291,5 @@ define(["connectionManager", "userSettings", "events"], function(connectionManag
getCurrentLocale: getCurrentLocale,
getCurrentDateTimeLocale: getCurrentDateTimeLocale,
register: register
}
};
});
@@ -1,71 +1,172 @@
define(["dialogHelper", "globalize", "userSettings", "layoutManager", "connectionManager", "require", "loading", "scrollHelper", "emby-checkbox", "emby-radio", "css!./../formdialog", "material-icons"], function(dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
"use strict";
define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectionManager', 'require', 'loading', 'scrollHelper', 'emby-checkbox', 'emby-radio', 'css!./../formdialog', 'material-icons'], function (dialogHelper, globalize, userSettings, layoutManager, connectionManager, require, loading, scrollHelper) {
'use strict';
function saveCategories(context, options) {
for (var categories = [], chkCategorys = context.querySelectorAll(".chkCategory"), i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute("data-type");
chkCategorys[i].checked && categories.push(type)
var categories = [];
var chkCategorys = context.querySelectorAll('.chkCategory');
for (var i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute('data-type');
if (chkCategorys[i].checked) {
categories.push(type);
}
}
categories.length >= 4 && categories.push("series"), categories.push("all"), options.categories = categories
if (categories.length >= 4) {
categories.push('series');
}
// differentiate between none and all
categories.push('all');
options.categories = categories;
}
function loadCategories(context, options) {
for (var selectedCategories = options.categories || [], chkCategorys = context.querySelectorAll(".chkCategory"), i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute("data-type");
chkCategorys[i].checked = !selectedCategories.length || -1 !== selectedCategories.indexOf(type)
var selectedCategories = options.categories || [];
var chkCategorys = context.querySelectorAll('.chkCategory');
for (var i = 0, length = chkCategorys.length; i < length; i++) {
var type = chkCategorys[i].getAttribute('data-type');
chkCategorys[i].checked = !selectedCategories.length || selectedCategories.indexOf(type) !== -1;
}
}
function save(context) {
var i, length, chkIndicators = context.querySelectorAll(".chkIndicator");
var i, length;
var chkIndicators = context.querySelectorAll('.chkIndicator');
for (i = 0, length = chkIndicators.length; i < length; i++) {
var type = chkIndicators[i].getAttribute("data-type");
userSettings.set("guide-indicator-" + type, chkIndicators[i].checked)
var type = chkIndicators[i].getAttribute('data-type');
userSettings.set('guide-indicator-' + type, chkIndicators[i].checked);
}
userSettings.set("guide-colorcodedbackgrounds", context.querySelector(".chkColorCodedBackgrounds").checked), userSettings.set("livetv-favoritechannelsattop", context.querySelector(".chkFavoriteChannelsAtTop").checked);
var sortBys = context.querySelectorAll(".chkSortOrder");
for (i = 0, length = sortBys.length; i < length; i++)
userSettings.set('guide-colorcodedbackgrounds', context.querySelector('.chkColorCodedBackgrounds').checked);
userSettings.set('livetv-favoritechannelsattop', context.querySelector('.chkFavoriteChannelsAtTop').checked);
var sortBys = context.querySelectorAll('.chkSortOrder');
for (i = 0, length = sortBys.length; i < length; i++) {
if (sortBys[i].checked) {
userSettings.set("livetv-channelorder", sortBys[i].value);
break
userSettings.set('livetv-channelorder', sortBys[i].value);
break;
}
}
}
function load(context) {
var i, length, chkIndicators = context.querySelectorAll(".chkIndicator");
var i, length;
var chkIndicators = context.querySelectorAll('.chkIndicator');
for (i = 0, length = chkIndicators.length; i < length; i++) {
var type = chkIndicators[i].getAttribute("data-type");
"true" === chkIndicators[i].getAttribute("data-default") ? chkIndicators[i].checked = "false" !== userSettings.get("guide-indicator-" + type) : chkIndicators[i].checked = "true" === userSettings.get("guide-indicator-" + type)
var type = chkIndicators[i].getAttribute('data-type');
if (chkIndicators[i].getAttribute('data-default') === 'true') {
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) !== 'false';
} else {
chkIndicators[i].checked = userSettings.get('guide-indicator-' + type) === 'true';
}
}
context.querySelector('.chkColorCodedBackgrounds').checked = userSettings.get('guide-colorcodedbackgrounds') === 'true';
context.querySelector('.chkFavoriteChannelsAtTop').checked = userSettings.get('livetv-favoritechannelsattop') !== 'false';
var sortByValue = userSettings.get('livetv-channelorder') || 'Number';
var sortBys = context.querySelectorAll('.chkSortOrder');
for (i = 0, length = sortBys.length; i < length; i++) {
sortBys[i].checked = sortBys[i].value === sortByValue;
}
}
function onSortByChange() {
var newValue = this.value;
if (this.checked) {
var changed = options.query.SortBy !== newValue;
options.query.SortBy = newValue.replace('_', ',');
options.query.StartIndex = 0;
if (options.callback && changed) {
options.callback();
}
}
context.querySelector(".chkColorCodedBackgrounds").checked = "true" === userSettings.get("guide-colorcodedbackgrounds"), context.querySelector(".chkFavoriteChannelsAtTop").checked = "false" !== userSettings.get("livetv-favoritechannelsattop");
var sortByValue = userSettings.get("livetv-channelorder") || "Number",
sortBys = context.querySelectorAll(".chkSortOrder");
for (i = 0, length = sortBys.length; i < length; i++) sortBys[i].checked = sortBys[i].value === sortByValue
}
function showEditor(options) {
return new Promise(function(resolve, reject) {
var settingsChanged = !1;
require(["text!./guide-settings.template.html"], function(template) {
return new Promise(function (resolve, reject) {
var settingsChanged = false;
require(['text!./guide-settings.template.html'], function (template) {
var dialogOptions = {
removeOnClose: !0,
scrollY: !1
removeOnClose: true,
scrollY: false
};
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "small";
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'small';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog");
var html = "";
html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, dlg.addEventListener("change", function() {
settingsChanged = !0
}), dlg.addEventListener("close", function() {
layoutManager.tv && scrollHelper.centerFocus.off(dlg.querySelector(".formDialogContent"), !1), save(dlg), saveCategories(dlg, options), settingsChanged ? resolve() : reject()
}), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg)
}), layoutManager.tv && scrollHelper.centerFocus.on(dlg.querySelector(".formDialogContent"), !1), load(dlg), loadCategories(dlg, options), dialogHelper.open(dlg)
})
})
dlg.classList.add('formDialog');
var html = '';
html += globalize.translateDocument(template, 'sharedcomponents');
dlg.innerHTML = html;
dlg.addEventListener('change', function () {
settingsChanged = true;
});
dlg.addEventListener('close', function () {
if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false);
}
save(dlg);
saveCategories(dlg, options);
if (settingsChanged) {
resolve();
} else {
reject();
}
});
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false);
}
load(dlg);
loadCategories(dlg, options);
dialogHelper.open(dlg);
});
});
}
return {
show: showEditor
}
};
});
+145 -246
View File
@@ -1,194 +1,141 @@
.tvGuideHeader,
.tvguide {
display: -webkit-box;
display: -webkit-flex
}
.channelPrograms,
.programContainer,
.timeslotHeadersInner,
.tvProgram {
position: relative
}
.channelPrograms,
.channelsContainer,
.tvGuideHeader,
.tvguide {
-webkit-box-orient: vertical;
-webkit-box-direction: normal
}
.guideChannelName,
.guideChannelNumber,
.guideProgramName,
.guideProgramNameText {
-o-text-overflow: ellipsis
}
.tvguide {
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-align: initial;
-webkit-align-items: initial;
align-items: initial
align-items: initial;
}
.tvGuideHeader {
white-space: nowrap;
width: 100%;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-flex-shrink: 0;
flex-shrink: 0;
display: flex;
contain: layout style paint
contain: layout style paint;
}
.layout-desktop .tvGuideHeader {
margin-bottom: .5em
margin-bottom: .5em;
}
.guideHeaderDateSelection {
font-size: 86%;
padding: .4em 0
padding: .4em 0;
}
.guide-headerTimeslots {
display: -webkit-box;
display: -webkit-flex;
display: flex
display: flex;
}
.tvProgramSectionHeader {
margin: 0
margin: 0;
}
.tvProgram {
display: block;
text-decoration: none;
white-space: nowrap
white-space: nowrap;
position: relative;
}
.guideProgramIndicator {
text-transform: uppercase;
-webkit-border-radius: .25em;
border-radius: .25em;
margin-right: .5em;
font-size: 82%;
padding: .2em .25em;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
text-align: center;
margin-left: 1em
margin-left: 1em;
}
.guide-channelTimeslotHeader {
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center
flex-shrink: 0;
justify-content: center;
}
.timeslotHeaders {
white-space: nowrap;
font-weight: 500;
font-size: 120%
font-size: 120%;
}
.programContainer {
white-space: nowrap;
-webkit-box-align: start;
-webkit-align-items: flex-start;
position: relative;
align-items: flex-start;
contain: strict
contain: strict;
}
.channelPrograms {
white-space: nowrap;
position: relative;
contain: strict;
box-sizing: border-box;
}
.timeslotHeadersInner {
position: relative;
}
.guideSpacer {
width: .3em;
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.channelPrograms,
.timeslotHeadersInner {
width: 1800vw
.channelPrograms, .timeslotHeadersInner {
width: 1800vw;
}
@media all and (min-width:37.5em) {
@media all and (min-width: 37.5em) {
.channelPrograms,
.timeslotHeadersInner {
width: 1400vw
.channelPrograms, .timeslotHeadersInner {
width: 1400vw;
}
}
@media all and (min-width:50em) {
@media all and (min-width: 50em) {
.channelPrograms,
.timeslotHeadersInner {
width: 1200vw
.channelPrograms, .timeslotHeadersInner {
width: 1200vw;
}
}
@media all and (min-width:80em) {
@media all and (min-width: 80em) {
.channelPrograms,
.timeslotHeadersInner {
width: 810vw
.channelPrograms, .timeslotHeadersInner {
width: 810vw;
}
}
.timeslotHeader {
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: inline-flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
text-indent: .25em;
width: 2.0833333333333333333333333333333%
width: 2.0833333333333333333333333333333%;
}
.guide-channelHeaderCell,
.guide-channelTimeslotHeader,
.programCell {
color: inherit;
.guide-channelHeaderCell, .guide-channelTimeslotHeader {
padding: 0 !important;
cursor: pointer;
outline: none !important;
width: 100%;
vertical-align: middle;
font-family: inherit;
text-decoration: none;
-webkit-box-align: center;
text-align: left;
overflow: hidden
}
.guide-channelHeaderCell,
.guide-channelTimeslotHeader {
padding: 0 !important;
outline: 0 !important;
width: 100%;
font-size: inherit;
-o-text-overflow: ellipsis;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 1px 0 0;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
text-decoration: none;
/* Needed in firefox */
text-align: left;
contain: strict;
-webkit-flex-shrink: 0;
flex-shrink: 0;
-webkit-border-radius: .12em;
border-radius: .12em
border-radius: .12em;
color: inherit;
}
.guide-channelHeaderCell {
@@ -198,187 +145,151 @@
height: 4.42em;
contain: strict;
position: relative;
background: 0 0
background: transparent;
}
.guide-channelTimeslotHeader {
border: 0 !important;
border-right-color: transparent
}
.channelsContainer,
.guide-channelTimeslotHeader {
width: 24vw
/* Important - have to put the fixed width on channelsContainer, not the individual channelHeaderCell
This was causing channelsContainer to extend beyond the fixed width on ps4, tizen, lg and opera tv.
*/
.channelsContainer, .guide-channelTimeslotHeader {
width: 24vw;
}
@media all and (min-width:31.25em) {
.channelsContainer,
.guide-channelTimeslotHeader {
width: 16vw
.channelsContainer, .guide-channelTimeslotHeader {
width: 16vw;
}
}
@media all and (min-width:37.5em) {
.channelsContainer,
.guide-channelTimeslotHeader {
width: 16vw
.channelsContainer, .guide-channelTimeslotHeader {
width: 16vw;
}
}
@media all and (min-width:50em) {
.channelsContainer,
.guide-channelTimeslotHeader {
width: 14vw
.channelsContainer, .guide-channelTimeslotHeader {
width: 14vw;
}
}
@media all and (min-width:80em) {
.channelsContainer,
.guide-channelTimeslotHeader {
width: 12vw
.channelsContainer, .guide-channelTimeslotHeader {
width: 12vw;
}
}
.btnGuideViewSettings {
margin: 0;
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.btnGuideViewSettingsIcon {
font-size: 1.5em !important
font-size: 1.5em !important;
}
.selectDateIcon {
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
@media all and (max-width:50em) {
@media all and (max-width: 50em) {
.guideHdIcon,
.liveTvProgram,
.newTvProgram,
.premiereTvProgram {
display: none
.newTvProgram, .liveTvProgram, .premiereTvProgram, .guideHdIcon {
display: none;
}
}
.channelPrograms,
.programCell {
border-style: solid;
display: -webkit-box;
display: -webkit-flex;
contain: strict
}
.channelPrograms {
white-space: nowrap;
-webkit-box-sizing: border-box;
box-sizing: border-box;
height: 4.42em;
contain: strict;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
border-width: 1px 0
border-style: solid;
border-width: 1px 0 1px 0;
}
.channelPrograms+.channelPrograms,
.guide-channelHeaderCell+.guide-channelHeaderCell {
margin-top: -1px
.channelPrograms + .channelPrograms, .guide-channelHeaderCell + .guide-channelHeaderCell {
margin-top: -1px;
}
.channelPrograms-tv, .guide-channelHeaderCell-tv {
height: 3em;
}
.channelPrograms-tv,
.guide-channelHeaderCell-tv {
height: 3em
.guide-channelTimeslotHeader {
border-right-color: transparent;
}
.guide-channelTimeslotHeader,
.timeslotHeader {
background: 0 0 !important;
height: 2.8em
.guide-channelTimeslotHeader, .timeslotHeader {
background: transparent !important;
height: 2.8em;
}
.programGrid {
padding-bottom: 4px;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1
flex-grow: 1;
}
.programCell {
background: 0 0;
color: inherit;
background: transparent;
border-style: solid;
border-width: 0 0 0 1px;
padding: 0 !important;
cursor: pointer;
outline: none !important;
width: 100%;
vertical-align: middle;
font-family: inherit;
font-size: inherit;
position: absolute;
top: 0;
bottom: 0;
display: flex;
-webkit-align-items: center;
text-decoration: none;
overflow: hidden;
align-items: center;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
/* Needed for Firefox */
text-align: left;
contain: strict;
flex-grow: 1;
margin: 0 !important
}
.channelsContainer,
.guideProgramName,
.programGrid {
contain: layout style paint
}
.guide-programNameCaret,
.guideProgramName {
display: -webkit-box;
display: -webkit-flex;
-webkit-box-align: center
margin: 0 !important;
}
.guideProgramName {
padding: 0 .7em;
padding: 0 .7em 0;
overflow: hidden;
text-overflow: ellipsis;
-webkit-align-items: center;
align-items: center;
display: flex;
position: relative;
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
flex-grow: 1
flex-grow: 1;
contain: layout style paint;
/*transition: transform 60ms ease-out;*/
}
.guide-programNameCaret {
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
font-size: 200%
font-size: 200%;
}
.guideProgramNameText {
margin: 0;
font-weight: 400;
font-weight: normal;
overflow: hidden;
text-overflow: ellipsis
text-overflow: ellipsis;
}
.guideProgramSecondaryInfo {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
margin-top: .1em
margin-top: .1em;
}
.programIcon {
@@ -387,26 +298,22 @@
width: 1em;
font-size: 1.6em;
color: #ddd;
-webkit-flex-shrink: 0;
flex-shrink: 0;
-webkit-box-flex: 0;
-webkit-flex-grow: 0;
flex-grow: 0
flex-grow: 0;
}
.guide-programTextIcon {
font-weight: 700;
font-weight: bold;
font-size: .9em;
padding: .16em .3em;
-webkit-border-radius: .25em;
border-radius: .25em;
margin-right: .35em;
width: auto;
height: auto
height: auto;
}
.guide-programTextIcon-tv {
font-size: .74em
font-size: .74em;
}
.guideChannelNumber {
@@ -414,8 +321,8 @@
max-width: 30%;
text-overflow: ellipsis;
overflow: hidden;
font-weight: 400;
margin: 0
font-weight: normal;
margin: 0;
}
.guideChannelName {
@@ -423,7 +330,7 @@
margin-right: 1em;
text-overflow: ellipsis;
overflow: hidden;
max-width: 70%
max-width: 70%;
}
.guideChannelImage {
@@ -432,68 +339,62 @@
top: 15%;
bottom: 15%;
width: 40%;
-webkit-background-size: contain;
background-size: contain;
background-repeat: no-repeat;
background-position: right center
background-position: right center;
}
@media all and (min-width:62.5em) {
@media all and (min-width: 62.5em) {
.guideChannelName {
max-width: 40%
max-width: 40%;
}
}
@media all and (max-width:62.5em) {
@media all and (max-width: 62.5em) {
.guideChannelNumber {
display: none
display: none;
}
.guideChannelImage {
width: 70%
width: 70%;
}
}
.channelsContainer {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-flex-shrink: 0;
flex-shrink: 0;
-webkit-flex-direction: column;
flex-direction: column
flex-direction: column;
}
.guide-channelHeaderCell,
.programCell {
outline: 0 !important
.channelsContainer, .programGrid {
contain: layout style paint;
}
.seriesTimerIcon,
.timerIcon {
color: #c33 !important
.programCell, .guide-channelHeaderCell {
outline: none !important;
}
.timerIcon, .seriesTimerIcon {
color: #cc3333 !important;
}
.seriesTimerIcon-inactive {
color: inherit !important;
opacity: .7
opacity: .7;
}
.guideOptions {
-webkit-flex-shrink: 0;
flex-shrink: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center
align-items: center;
}
@media all and (max-width:50em),
all and (max-height:37.5em) {
@media all and (max-width: 50em), all and (max-height: 37.5em) {
.tvGuideHeader {
padding-left: 0
padding-left: 0;
}
}
@@ -501,31 +402,29 @@ all and (max-height:37.5em) {
margin: 1em auto;
text-align: center;
padding: 1em;
-webkit-flex-shrink: 0;
flex-shrink: 0
flex-shrink: 0;
}
.noRubberBanding {
padding-bottom: 7em
/* This is needed to combat the rubber banding in iOS */
padding-bottom: 7em;
}
.guideDateTabsSlider {
text-align: center
text-align: center;
}
.guide-date-tab-button {
padding: .3em .7em !important;
margin: 0 .3em !important;
font-weight: 400
font-weight: normal;
}
.guide-date-tab-button.emby-tab-button-active {
border-color: transparent !important
}
.guide-date-tab-button.emby-tab-button-active {
border-color: transparent !important;
}
.guide-date-tab-button.emby-button-tv:focus {
-webkit-border-radius: .15em !important;
border-radius: .15em !important;
-webkit-transform: none !important;
transform: none !important
}
.guide-date-tab-button.emby-button-tv:focus {
border-radius: .15em !important;
transform: none !important;
}
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -1,19 +1,19 @@
.newTvProgram {
background: #38c;
color: #fff
background: #3388cc;
color: #fff;
}
.liveTvProgram {
background: #c33;
color: #fff
background: #cc3333;
color: #fff;
}
.premiereTvProgram {
background: #EF6C00;
color: #fff
color: #fff;
}
.repeatTvProgram {
background: #009688;
color: #fff
}
color: #fff;
}
@@ -1,15 +1,11 @@
.headroom {
-webkit-transition: -webkit-transform 140ms linear;
-o-transition: transform 140ms linear;
transition: transform 140ms linear
transition: transform 140ms linear;
}
.headroom--pinned {
-webkit-transform: none;
transform: none
transform: none;
}
.headroom--unpinned:not(.headroomDisabled) {
-webkit-transform: translateY(-100%);
transform: translateY(-100%)
transform: translateY(-100%);
}
+306 -93
View File
@@ -1,136 +1,349 @@
define(["dom", "layoutManager", "browser", "css!./headroom"], function(dom, layoutManager, browser) {
"use strict";
/*!
* headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it
* Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js
* License: MIT
*/
define(['dom', 'layoutManager', 'browser', 'css!./headroom'], function (dom, layoutManager, browser) {
'use strict';
/* exported features */
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
/**
* Handles debouncing of events via requestAnimationFrame
* @see http://www.html5rocks.com/en/tutorials/speed/animations/
* @param {Function} callback The callback to handle whichever event
*/
function Debouncer(callback) {
this.callback = callback, this.ticking = !1
this.callback = callback;
this.ticking = false;
}
Debouncer.prototype = {
constructor: Debouncer,
/**
* dispatches the event to the supplied callback
* @private
*/
update: function () {
if (this.callback) {
this.callback();
}
this.ticking = false;
},
/**
* Attach this as the event listeners
*/
handleEvent: function () {
if (!this.ticking) {
requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
this.ticking = true;
}
}
};
function onHeadroomClearedExternally() {
this.state = null
this.state = null;
}
/**
* UI enhancement for fixed headers.
* Hides header when scrolling down
* Shows header when scrolling up
* @constructor
* @param {DOMElement} elem the header element
* @param {Object} options options for the widget
*/
function Headroom(elems, options) {
options = Object.assign(Headroom.options, options || {}), this.lastKnownScrollY = 0, this.elems = elems, this.scroller = options.scroller, this.debouncer = onScroll.bind(this), this.offset = options.offset, this.initialised = !1, this.initialClass = options.initialClass, this.unPinnedClass = options.unPinnedClass, this.pinnedClass = options.pinnedClass, this.state = "clear"
options = Object.assign(Headroom.options, options || {});
this.lastKnownScrollY = 0;
this.elems = elems;
this.scroller = options.scroller;
this.debouncer = onScroll.bind(this);
this.offset = options.offset;
this.initialised = false;
this.initialClass = options.initialClass;
this.unPinnedClass = options.unPinnedClass;
this.pinnedClass = options.pinnedClass;
this.state = 'clear';
}
function onScroll() {
this.paused || requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)))
}
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
return Debouncer.prototype = {
constructor: Debouncer,
update: function() {
this.callback && this.callback(), this.ticking = !1
},
handleEvent: function() {
this.ticking || (requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))), this.ticking = !0)
if (this.paused) {
return;
}
}, Headroom.prototype = {
requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
}
Headroom.prototype = {
constructor: Headroom,
init: function() {
/**
* Initialises the widget
*/
init: function () {
if (browser.supportsCssAnimation()) {
for (var i = 0, length = this.elems.length; i < length; i++) this.elems[i].classList.add(this.initialClass), this.elems[i].addEventListener("clearheadroom", onHeadroomClearedExternally.bind(this));
this.attachEvent()
for (var i = 0, length = this.elems.length; i < length; i++) {
this.elems[i].classList.add(this.initialClass);
this.elems[i].addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this));
}
this.attachEvent();
}
return this
return this;
},
add: function(elem) {
browser.supportsCssAnimation() && (elem.classList.add(this.initialClass), elem.addEventListener("clearheadroom", onHeadroomClearedExternally.bind(this)), this.elems.push(elem))
add: function (elem) {
if (browser.supportsCssAnimation()) {
elem.classList.add(this.initialClass);
elem.addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this));
this.elems.push(elem);
}
},
remove: function(elem) {
elem.classList.remove(this.unPinnedClass), elem.classList.remove(this.initialClass), elem.classList.remove(this.pinnedClass);
var i = this.elems.indexOf(elem); - 1 !== i && this.elems.splice(i, 1)
remove: function (elem) {
elem.classList.remove(this.unPinnedClass);
elem.classList.remove(this.initialClass);
elem.classList.remove(this.pinnedClass);
var i = this.elems.indexOf(elem);
if (i !== -1) {
this.elems.splice(i, 1);
}
},
pause: function() {
this.paused = !0
pause: function () {
this.paused = true;
},
resume: function() {
this.paused = !1
resume: function () {
this.paused = false;
},
destroy: function() {
this.initialised = !1;
/**
* Unattaches events and removes any classes that were added
*/
destroy: function () {
this.initialised = false;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.remove(this.unPinnedClass);
classList.remove(this.initialClass);
classList.remove(this.pinnedClass);
}
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll';
dom.removeEventListener(this.scroller, scrollEventName, this.debouncer, {
capture: false,
passive: true
});
},
/**
* Attaches the scroll event
* @private
*/
attachEvent: function () {
if (!this.initialised) {
this.lastKnownScrollY = this.getScrollY();
this.initialised = true;
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : 'scroll';
dom.addEventListener(this.scroller, scrollEventName, this.debouncer, {
capture: false,
passive: true
});
this.update();
}
},
/**
* Unpins the header if it's currently pinned
*/
clear: function () {
if (this.state === 'clear') {
return;
}
this.state = 'clear';
var unpinnedClass = this.unPinnedClass;
var pinnedClass = this.pinnedClass;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.remove(this.unPinnedClass), classList.remove(this.initialClass), classList.remove(this.pinnedClass)
}
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : "scroll";
dom.removeEventListener(this.scroller, scrollEventName, this.debouncer, {
capture: !1,
passive: !0
})
},
attachEvent: function() {
if (!this.initialised) {
this.lastKnownScrollY = this.getScrollY(), this.initialised = !0;
var scrollEventName = this.scroller.getScrollEventName ? this.scroller.getScrollEventName() : "scroll";
dom.addEventListener(this.scroller, scrollEventName, this.debouncer, {
capture: !1,
passive: !0
}), this.update()
classList.remove(unpinnedClass);
//classList.remove(pinnedClass);
}
},
clear: function() {
if ("clear" !== this.state) {
this.state = "clear";
for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) {
this.elems[i].classList.remove(unpinnedClass)
}
/**
* Unpins the header if it's currently pinned
*/
pin: function () {
if (this.state === 'pin') {
return;
}
this.state = 'pin';
var unpinnedClass = this.unPinnedClass;
var pinnedClass = this.pinnedClass;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.remove(unpinnedClass);
classList.add(pinnedClass);
}
},
pin: function() {
if ("pin" !== this.state) {
this.state = "pin";
for (var unpinnedClass = this.unPinnedClass, pinnedClass = this.pinnedClass, i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.remove(unpinnedClass), classList.add(pinnedClass)
}
/**
* Unpins the header if it's currently pinned
*/
unpin: function () {
if (this.state === 'unpin') {
return;
}
this.state = 'unpin';
var unpinnedClass = this.unPinnedClass;
var pinnedClass = this.pinnedClass;
for (var i = 0, length = this.elems.length; i < length; i++) {
var classList = this.elems[i].classList;
classList.add(unpinnedClass);
//classList.remove(pinnedClass);
}
},
unpin: function() {
if ("unpin" !== this.state) {
this.state = "unpin";
for (var unpinnedClass = this.unPinnedClass, i = (this.pinnedClass, 0), length = this.elems.length; i < length; i++) {
this.elems[i].classList.add(unpinnedClass)
}
}
},
getScrollY: function() {
/**
* Gets the Y scroll position
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
* @return {Number} pixels the page has scrolled along the Y-axis
*/
getScrollY: function () {
var scroller = this.scroller;
if (scroller.getScrollPosition) return scroller.getScrollPosition();
if (scroller.getScrollPosition) {
return scroller.getScrollPosition();
}
var pageYOffset = scroller.pageYOffset;
if (void 0 !== pageYOffset) return pageYOffset;
if (pageYOffset !== undefined) {
return pageYOffset;
}
var scrollTop = scroller.scrollTop;
return void 0 !== scrollTop ? scrollTop : (document.documentElement || document.body).scrollTop
if (scrollTop !== undefined) {
return scrollTop;
}
return (document.documentElement || document.body).scrollTop;
},
shouldUnpin: function(currentScrollY) {
/**
* determine if it is appropriate to unpin
* @param {int} currentScrollY the current y scroll position
* @return {bool} true if should unpin, false otherwise
*/
shouldUnpin: function (currentScrollY) {
var scrollingDown = currentScrollY > this.lastKnownScrollY,
pastOffset = currentScrollY >= this.offset;
return scrollingDown && pastOffset
return scrollingDown && pastOffset;
},
shouldPin: function(currentScrollY) {
/**
* determine if it is appropriate to pin
* @param {int} currentScrollY the current y scroll position
* @return {bool} true if should pin, false otherwise
*/
shouldPin: function (currentScrollY) {
var scrollingUp = currentScrollY < this.lastKnownScrollY,
pastOffset = currentScrollY <= this.offset;
return scrollingUp || pastOffset
return scrollingUp || pastOffset;
},
update: function() {
if (!this.paused) {
var currentScrollY = this.getScrollY(),
lastKnownScrollY = this.lastKnownScrollY,
isTv = layoutManager.tv;
if (currentScrollY <= (isTv ? 120 : 10)) this.clear();
else if (this.shouldUnpin(currentScrollY)) this.unpin();
else if (this.shouldPin(currentScrollY)) {
var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14;
currentScrollY && isTv ? this.unpin() : toleranceExceeded && this.clear()
}
this.lastKnownScrollY = currentScrollY
/**
* Handles updating the state of the widget
*/
update: function () {
if (this.paused) {
return;
}
var currentScrollY = this.getScrollY();
var lastKnownScrollY = this.lastKnownScrollY;
var isTv = layoutManager.tv;
if (currentScrollY <= (isTv ? 120 : 10)) {
this.clear();
}
else if (this.shouldUnpin(currentScrollY)) {
this.unpin();
}
else if (this.shouldPin(currentScrollY)) {
var toleranceExceeded = Math.abs(currentScrollY - lastKnownScrollY) >= 14;
if (currentScrollY && isTv) {
this.unpin();
} else if (toleranceExceeded) {
this.clear();
}
} else if (isTv) {
//this.clear();
}
this.lastKnownScrollY = currentScrollY;
}
}, Headroom.options = {
};
/**
* Default options
* @type {Object}
*/
Headroom.options = {
offset: 0,
scroller: window,
initialClass: "headroom",
unPinnedClass: "headroom--unpinned",
pinnedClass: "headroom--pinned"
}, Headroom
initialClass: 'headroom',
unPinnedClass: 'headroom--unpinned',
pinnedClass: 'headroom--pinned'
};
return Headroom;
});
@@ -1,233 +1,543 @@
define(["require", "apphost", "layoutManager", "focusManager", "globalize", "loading", "connectionManager", "homeSections", "dom", "events", "listViewStyle", "emby-select", "emby-checkbox"], function(require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) {
define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loading', 'connectionManager', 'homeSections', 'dom', 'events', 'listViewStyle', 'emby-select', 'emby-checkbox'], function (require, appHost, layoutManager, focusManager, globalize, loading, connectionManager, homeSections, dom, events) {
"use strict";
var numConfigurableSections = 7;
function renderViews(page, user, result) {
var folderHtml = "";
folderHtml += '<div class="checkboxList">', folderHtml += result.map(function(i) {
var currentHtml = "",
id = "chkGroupFolder" + i.Id,
isChecked = -1 !== user.Configuration.GroupedFolders.indexOf(i.Id),
checkedHtml = isChecked ? ' checked="checked"' : "";
return currentHtml += "<label>", currentHtml += '<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="' + i.Id + '" id="' + id + '"' + checkedHtml + "/>", currentHtml += "<span>" + i.Name + "</span>", currentHtml += "</label>"
}).join(""), folderHtml += "</div>", page.querySelector(".folderGroupList").innerHTML = folderHtml
var folderHtml = '';
folderHtml += '<div class="checkboxList">';
folderHtml += result.map(function (i) {
var currentHtml = '';
var id = 'chkGroupFolder' + i.Id;
var isChecked = user.Configuration.GroupedFolders.indexOf(i.Id) !== -1;
var checkedHtml = isChecked ? ' checked="checked"' : '';
currentHtml += '<label>';
currentHtml += '<input type="checkbox" is="emby-checkbox" class="chkGroupFolder" data-folderid="' + i.Id + '" id="' + id + '"' + checkedHtml + '/>';
currentHtml += '<span>' + i.Name + '</span>';
currentHtml += '</label>';
return currentHtml;
}).join('');
folderHtml += '</div>';
page.querySelector('.folderGroupList').innerHTML = folderHtml;
}
function getLandingScreenOptions(type) {
var list = [];
return "movies" === type ? (list.push({
name: globalize.translate("sharedcomponents#Movies"),
value: "movies",
isDefault: !0
}), list.push({
name: globalize.translate("sharedcomponents#Suggestions"),
value: "suggestions"
}), list.push({
name: globalize.translate("sharedcomponents#Favorites"),
value: "favorites"
}), list.push({
name: globalize.translate("sharedcomponents#Collections"),
value: "collections"
})) : "tvshows" === type ? (list.push({
name: globalize.translate("sharedcomponents#Shows"),
value: "shows",
isDefault: !0
}), list.push({
name: globalize.translate("sharedcomponents#Suggestions"),
value: "suggestions"
}), list.push({
name: globalize.translate("sharedcomponents#Latest"),
value: "latest"
}), list.push({
name: globalize.translate("sharedcomponents#Favorites"),
value: "favorites"
})) : "music" === type ? (list.push({
name: globalize.translate("sharedcomponents#Suggestions"),
value: "suggestions",
isDefault: !0
}), list.push({
name: globalize.translate("sharedcomponents#Albums"),
value: "albums"
}), list.push({
name: globalize.translate("sharedcomponents#HeaderAlbumArtists"),
value: "albumartists"
}), list.push({
name: globalize.translate("sharedcomponents#Artists"),
value: "artists"
}), list.push({
name: globalize.translate("sharedcomponents#Playlists"),
value: "playlists"
}), list.push({
name: globalize.translate("sharedcomponents#Genres"),
value: "genres"
})) : "livetv" === type && (list.push({
name: globalize.translate("sharedcomponents#Suggestions"),
value: "suggestions",
isDefault: !0
}), list.push({
name: globalize.translate("sharedcomponents#Guide"),
value: "guide"
})), list
if (type === 'movies') {
list.push({
name: globalize.translate('sharedcomponents#Movies'),
value: 'movies',
isDefault: true
});
list.push({
name: globalize.translate('sharedcomponents#Suggestions'),
value: 'suggestions'
});
list.push({
name: globalize.translate('sharedcomponents#Favorites'),
value: 'favorites'
});
list.push({
name: globalize.translate('sharedcomponents#Collections'),
value: 'collections'
});
}
else if (type === 'tvshows') {
list.push({
name: globalize.translate('sharedcomponents#Shows'),
value: 'shows',
isDefault: true
});
list.push({
name: globalize.translate('sharedcomponents#Suggestions'),
value: 'suggestions'
});
list.push({
name: globalize.translate('sharedcomponents#Latest'),
value: 'latest'
});
list.push({
name: globalize.translate('sharedcomponents#Favorites'),
value: 'favorites'
});
}
else if (type === 'music') {
list.push({
name: globalize.translate('sharedcomponents#Suggestions'),
value: 'suggestions',
isDefault: true
});
list.push({
name: globalize.translate('sharedcomponents#Albums'),
value: 'albums'
});
list.push({
name: globalize.translate('sharedcomponents#HeaderAlbumArtists'),
value: 'albumartists'
});
list.push({
name: globalize.translate('sharedcomponents#Artists'),
value: 'artists'
});
list.push({
name: globalize.translate('sharedcomponents#Playlists'),
value: 'playlists'
});
list.push({
name: globalize.translate('sharedcomponents#Genres'),
value: 'genres'
});
}
else if (type === 'livetv') {
list.push({
name: globalize.translate('sharedcomponents#Suggestions'),
value: 'suggestions',
isDefault: true
});
list.push({
name: globalize.translate('sharedcomponents#Guide'),
value: 'guide'
});
}
return list;
}
function getLandingScreenOptionsHtml(type, userValue) {
return getLandingScreenOptions(type).map(function(o) {
var selected = userValue === o.value || o.isDefault && !userValue,
selectedHtml = selected ? " selected" : "";
return '<option value="' + (o.isDefault ? "" : o.value) + '"' + selectedHtml + ">" + o.name + "</option>"
}).join("")
return getLandingScreenOptions(type).map(function (o) {
var selected = userValue === o.value || (o.isDefault && !userValue);
var selectedHtml = selected ? ' selected' : '';
var optionValue = o.isDefault ? '' : o.value;
return '<option value="' + optionValue + '"' + selectedHtml + '>' + o.name + '</option>';
}).join('');
}
function renderViewOrder(context, user, result) {
var html = "",
index = 0;
html += result.Items.map(function(view) {
var currentHtml = "";
return currentHtml += '<div class="listItem viewItem" data-viewid="' + view.Id + '">', currentHtml += '<i class="md-icon listItemIcon">&#xE2C8;</i>', currentHtml += '<div class="listItemBody">', currentHtml += "<div>", currentHtml += view.Name, currentHtml += "</div>", currentHtml += "</div>", currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="' + globalize.translate("sharedcomponents#Up") + '"><i class="md-icon">&#xE316;</i></button>', currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate("sharedcomponents#Down") + '"><i class="md-icon">&#xE313;</i></button>', currentHtml += "</div>", index++, currentHtml
}).join(""), context.querySelector(".viewOrderList").innerHTML = html
var html = '';
var index = 0;
html += result.Items.map(function (view) {
var currentHtml = '';
currentHtml += '<div class="listItem viewItem" data-viewid="' + view.Id + '">';
currentHtml += '<i class="md-icon listItemIcon">&#xE2C8;</i>';
currentHtml += '<div class="listItemBody">';
currentHtml += '<div>';
currentHtml += view.Name;
currentHtml += '</div>';
currentHtml += '</div>';
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemUp btnViewItemMove autoSize" title="' + globalize.translate('sharedcomponents#Up') + '"><i class="md-icon">&#xE316;</i></button>';
currentHtml += '<button type="button" is="paper-icon-button-light" class="btnViewItemDown btnViewItemMove autoSize" title="' + globalize.translate('sharedcomponents#Down') + '"><i class="md-icon">&#xE313;</i></button>';
currentHtml += '</div>';
index++;
return currentHtml;
}).join('');
context.querySelector('.viewOrderList').innerHTML = html;
}
function updateHomeSectionValues(context, userSettings) {
for (var i = 1; i <= 7; i++) {
var select = context.querySelector("#selectHomeSection" + i),
defaultValue = homeSections.getDefaultSection(i - 1),
option = select.querySelector("option[value=" + defaultValue + "]") || select.querySelector('option[value=""]'),
userValue = userSettings.get("homesection" + (i - 1));
option.value = "", select.value = userValue !== defaultValue && userValue ? userValue : ""
var select = context.querySelector('#selectHomeSection' + i);
var defaultValue = homeSections.getDefaultSection(i - 1);
var option = select.querySelector('option[value=' + defaultValue + ']') || select.querySelector('option[value=""]');
var userValue = userSettings.get('homesection' + (i - 1));
option.value = '';
if (userValue === defaultValue || !userValue) {
select.value = '';
} else {
select.value = userValue;
}
}
context.querySelector(".selectTVHomeScreen").value = userSettings.get("tvhome") || ""
context.querySelector('.selectTVHomeScreen').value = userSettings.get('tvhome') || '';
}
function getPerLibrarySettingsHtml(item, user, userSettings, apiClient) {
var isChecked, html = "";
if ("Channel" !== item.Type && "boxsets" !== item.CollectionType && "playlists" !== item.CollectionType || (isChecked = -1 === (user.Configuration.MyMediaExcludes || []).indexOf(item.Id), html += "<div>", html += "<label>", html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : "") + "/>", html += "<span>" + globalize.translate("sharedcomponents#DisplayInMyMedia") + "</span>", html += "</label>", html += "</div>"), -1 === ["playlists", "livetv", "boxsets", "channels"].indexOf(item.CollectionType || "") && (isChecked = -1 === user.Configuration.LatestItemsExcludes.indexOf(item.Id), html += '<label class="fldIncludeInLatest">', html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : "") + "/>", html += "<span>" + globalize.translate("sharedcomponents#DisplayInOtherHomeScreenSections") + "</span>", html += "</label>"), html && (html = '<div class="checkboxListContainer">' + html + "</div>"), "movies" === item.CollectionType || "tvshows" === item.CollectionType || "music" === item.CollectionType || "livetv" === item.CollectionType) {
var idForLanding = "livetv" === item.CollectionType ? item.CollectionType : item.Id;
html += '<div class="selectContainer">', html += '<select is="emby-select" class="selectLanding" data-folderid="' + idForLanding + '" label="' + globalize.translate("sharedcomponents#LabelDefaultScreen") + '">';
var userValue = userSettings.get("landing-" + idForLanding);
html += getLandingScreenOptionsHtml(item.CollectionType, userValue), html += "</select>", html += "</div>"
var html = '';
var isChecked;
if (item.Type === 'Channel' || item.CollectionType === 'boxsets' || item.CollectionType === 'playlists') {
isChecked = (user.Configuration.MyMediaExcludes || []).indexOf(item.Id) === -1;
html += '<div>';
html += '<label>';
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInMyMedia" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>';
html += '<span>' + globalize.translate('sharedcomponents#DisplayInMyMedia') + '</span>';
html += '</label>';
html += '</div>';
}
var excludeFromLatest = ['playlists', 'livetv', 'boxsets', 'channels'];
if (excludeFromLatest.indexOf(item.CollectionType || '') === -1) {
isChecked = user.Configuration.LatestItemsExcludes.indexOf(item.Id) === -1;
html += '<label class="fldIncludeInLatest">';
html += '<input type="checkbox" is="emby-checkbox" class="chkIncludeInLatest" data-folderid="' + item.Id + '"' + (isChecked ? ' checked="checked"' : '') + '/>';
html += '<span>' + globalize.translate('sharedcomponents#DisplayInOtherHomeScreenSections') + '</span>';
html += '</label>';
}
if (html) {
var prefix = "";
prefix += '<div class="verticalSection">', prefix += '<h2 class="sectionTitle">', prefix += item.Name, prefix += "</h2>", html = prefix + html, html += "</div>"
html = '<div class="checkboxListContainer">' + html + '</div>';
}
return html
if (item.CollectionType === 'movies' || item.CollectionType === 'tvshows' || item.CollectionType === 'music' || item.CollectionType === 'livetv') {
var idForLanding = item.CollectionType === 'livetv' ? item.CollectionType : item.Id;
html += '<div class="selectContainer">';
html += '<select is="emby-select" class="selectLanding" data-folderid="' + idForLanding + '" label="' + globalize.translate('sharedcomponents#LabelDefaultScreen') + '">';
var userValue = userSettings.get('landing-' + idForLanding);
html += getLandingScreenOptionsHtml(item.CollectionType, userValue);
html += '</select>';
html += '</div>';
}
if (html) {
var prefix = '';
prefix += '<div class="verticalSection">';
prefix += '<h2 class="sectionTitle">';
prefix += item.Name;
prefix += '</h2>';
html = prefix + html;
html += '</div>';
}
return html;
}
function renderPerLibrarySettings(context, user, userViews, userSettings, apiClient) {
for (var elem = context.querySelector(".perLibrarySettings"), html = "", i = 0, length = userViews.length; i < length; i++) html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
elem.innerHTML = html
var elem = context.querySelector('.perLibrarySettings');
var html = '';
for (var i = 0, length = userViews.length; i < length; i++) {
html += getPerLibrarySettingsHtml(userViews[i], user, userSettings, apiClient);
}
elem.innerHTML = html;
}
function loadForm(context, user, userSettings, apiClient) {
context.querySelector(".chkHidePlayedFromLatest").checked = user.Configuration.HidePlayedInLatest || !1, updateHomeSectionValues(context, userSettings);
var promise1 = apiClient.getUserViews({
IncludeHidden: !0
}, user.Id),
promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions"));
Promise.all([promise1, promise2]).then(function(responses) {
renderViewOrder(context, user, responses[0]), renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient), renderViews(context, user, responses[1]), loading.hide()
})
context.querySelector('.chkHidePlayedFromLatest').checked = user.Configuration.HidePlayedInLatest || false;
updateHomeSectionValues(context, userSettings);
var promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id);
var promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions"));
Promise.all([promise1, promise2]).then(function (responses) {
renderViewOrder(context, user, responses[0]);
renderPerLibrarySettings(context, user, responses[0].Items, userSettings, apiClient);
renderViews(context, user, responses[1]);
loading.hide();
});
}
function getSibling(elem, type, className) {
var sibling = elem[type];
while (sibling != null) {
if (sibling.classList.contains(className)) {
break;
}
}
if (sibling != null) {
if (!sibling.classList.contains(className)) {
sibling = null;
}
}
return sibling;
}
function onSectionOrderListClick(e) {
var target = dom.parentWithClass(e.target, "btnViewItemMove");
var target = dom.parentWithClass(e.target, 'btnViewItemMove');
if (target) {
var viewItem = dom.parentWithClass(target, "viewItem");
var viewItem = dom.parentWithClass(target, 'viewItem');
if (viewItem) {
dom.parentWithClass(viewItem, "paperList");
if (target.classList.contains("btnViewItemDown")) {
var ul = dom.parentWithClass(viewItem, 'paperList');
if (target.classList.contains('btnViewItemDown')) {
var next = viewItem.nextSibling;
next && (viewItem.parentNode.removeChild(viewItem), next.parentNode.insertBefore(viewItem, next.nextSibling))
if (next) {
viewItem.parentNode.removeChild(viewItem);
next.parentNode.insertBefore(viewItem, next.nextSibling);
}
} else {
var prev = viewItem.previousSibling;
prev && (viewItem.parentNode.removeChild(viewItem), prev.parentNode.insertBefore(viewItem, prev))
if (prev) {
viewItem.parentNode.removeChild(viewItem);
prev.parentNode.insertBefore(viewItem, prev);
}
}
}
}
}
function getCheckboxItems(selector, context, isChecked) {
for (var inputs = context.querySelectorAll(selector), list = [], i = 0, length = inputs.length; i < length; i++) inputs[i].checked === isChecked && list.push(inputs[i]);
return list
var inputs = context.querySelectorAll(selector);
var list = [];
for (var i = 0, length = inputs.length; i < length; i++) {
if (inputs[i].checked === isChecked) {
list.push(inputs[i]);
}
}
return list;
}
function saveUser(context, user, userSettingsInstance, apiClient) {
user.Configuration.HidePlayedInLatest = context.querySelector(".chkHidePlayedFromLatest").checked, user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, !1).map(function(i) {
return i.getAttribute("data-folderid")
}), user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, !1).map(function(i) {
return i.getAttribute("data-folderid")
}), user.Configuration.GroupedFolders = getCheckboxItems(".chkGroupFolder", context, !0).map(function(i) {
return i.getAttribute("data-folderid")
user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked;
user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, false).map(function (i) {
return i.getAttribute('data-folderid');
});
var i, length, viewItems = context.querySelectorAll(".viewItem"),
orderedViews = [];
for (i = 0, length = viewItems.length; i < length; i++) orderedViews.push(viewItems[i].getAttribute("data-viewid"));
user.Configuration.OrderedViews = orderedViews, userSettingsInstance.set("tvhome", context.querySelector(".selectTVHomeScreen").value), userSettingsInstance.set("homesection0", context.querySelector("#selectHomeSection1").value), userSettingsInstance.set("homesection1", context.querySelector("#selectHomeSection2").value), userSettingsInstance.set("homesection2", context.querySelector("#selectHomeSection3").value), userSettingsInstance.set("homesection3", context.querySelector("#selectHomeSection4").value), userSettingsInstance.set("homesection4", context.querySelector("#selectHomeSection5").value), userSettingsInstance.set("homesection5", context.querySelector("#selectHomeSection6").value), userSettingsInstance.set("homesection6", context.querySelector("#selectHomeSection7").value);
var selectLandings = context.querySelectorAll(".selectLanding");
user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, false).map(function (i) {
return i.getAttribute('data-folderid');
});
user.Configuration.GroupedFolders = getCheckboxItems(".chkGroupFolder", context, true).map(function (i) {
return i.getAttribute('data-folderid');
});
var viewItems = context.querySelectorAll('.viewItem');
var orderedViews = [];
var i, length;
for (i = 0, length = viewItems.length; i < length; i++) {
orderedViews.push(viewItems[i].getAttribute('data-viewid'));
}
user.Configuration.OrderedViews = orderedViews;
userSettingsInstance.set('tvhome', context.querySelector('.selectTVHomeScreen').value);
userSettingsInstance.set('homesection0', context.querySelector('#selectHomeSection1').value);
userSettingsInstance.set('homesection1', context.querySelector('#selectHomeSection2').value);
userSettingsInstance.set('homesection2', context.querySelector('#selectHomeSection3').value);
userSettingsInstance.set('homesection3', context.querySelector('#selectHomeSection4').value);
userSettingsInstance.set('homesection4', context.querySelector('#selectHomeSection5').value);
userSettingsInstance.set('homesection5', context.querySelector('#selectHomeSection6').value);
userSettingsInstance.set('homesection6', context.querySelector('#selectHomeSection7').value);
var selectLandings = context.querySelectorAll('.selectLanding');
for (i = 0, length = selectLandings.length; i < length; i++) {
var selectLanding = selectLandings[i];
userSettingsInstance.set("landing-" + selectLanding.getAttribute("data-folderid"), selectLanding.value)
userSettingsInstance.set('landing-' + selectLanding.getAttribute('data-folderid'), selectLanding.value);
}
return apiClient.updateUserConfiguration(user.Id, user.Configuration)
return apiClient.updateUserConfiguration(user.Id, user.Configuration);
}
function save(instance, context, userId, userSettings, apiClient, enableSaveConfirmation) {
loading.show(), apiClient.getUser(userId).then(function(user) {
saveUser(context, user, userSettings, apiClient).then(function() {
loading.hide(), enableSaveConfirmation && require(["toast"], function(toast) {
toast(globalize.translate("sharedcomponents#SettingsSaved"))
}), events.trigger(instance, "saved")
}, function() {
loading.hide()
})
})
loading.show();
apiClient.getUser(userId).then(function (user) {
saveUser(context, user, userSettings, apiClient).then(function () {
loading.hide();
if (enableSaveConfirmation) {
require(['toast'], function (toast) {
toast(globalize.translate('sharedcomponents#SettingsSaved'));
});
}
events.trigger(instance, 'saved');
}, function () {
loading.hide();
});
});
}
function onSubmit(e) {
var self = this,
apiClient = connectionManager.getApiClient(self.options.serverId),
userId = self.options.userId,
userSettings = self.options.userSettings;
return userSettings.setUserInfo(userId, apiClient).then(function() {
var self = this;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userId = self.options.userId;
var userSettings = self.options.userSettings;
userSettings.setUserInfo(userId, apiClient).then(function () {
var enableSaveConfirmation = self.options.enableSaveConfirmation;
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation)
}), e && e.preventDefault(), !1
save(self, self.options.element, userId, userSettings, apiClient, enableSaveConfirmation);
});
// Disable default form submission
if (e) {
e.preventDefault();
}
return false;
}
function onChange(e) {
var chkIncludeInMyMedia = dom.parentWithClass(e.target, "chkIncludeInMyMedia");
if (chkIncludeInMyMedia) {
var section = dom.parentWithClass(chkIncludeInMyMedia, "verticalSection"),
fldIncludeInLatest = section.querySelector(".fldIncludeInLatest");
fldIncludeInLatest && (chkIncludeInMyMedia.checked ? fldIncludeInLatest.classList.remove("hide") : fldIncludeInLatest.classList.add("hide"))
var chkIncludeInMyMedia = dom.parentWithClass(e.target, 'chkIncludeInMyMedia');
if (!chkIncludeInMyMedia) {
return;
}
var section = dom.parentWithClass(chkIncludeInMyMedia, 'verticalSection');
var fldIncludeInLatest = section.querySelector('.fldIncludeInLatest');
if (fldIncludeInLatest) {
if (chkIncludeInMyMedia.checked) {
fldIncludeInLatest.classList.remove('hide');
} else {
fldIncludeInLatest.classList.add('hide');
}
}
}
function embed(options, self) {
require(["text!./homescreensettings.template.html"], function(template) {
for (var i = 1; i <= numConfigurableSections; i++) template = template.replace("{section" + i + "label}", globalize.translate("sharedcomponents#LabelHomeScreenSectionValue", i));
options.element.innerHTML = globalize.translateDocument(template, "sharedcomponents"), options.element.querySelector(".viewOrderList").addEventListener("click", onSectionOrderListClick), options.element.querySelector("form").addEventListener("submit", onSubmit.bind(self)), options.element.addEventListener("change", onChange), options.enableSaveButton && options.element.querySelector(".btnSave").classList.remove("hide"), layoutManager.tv ? options.element.querySelector(".selectTVHomeScreenContainer").classList.remove("hide") : options.element.querySelector(".selectTVHomeScreenContainer").classList.add("hide"), self.loadData(options.autoFocus)
})
require(['text!./homescreensettings.template.html'], function (template) {
for (var i = 1; i <= numConfigurableSections; i++) {
template = template.replace('{section' + i + 'label}', globalize.translate('sharedcomponents#LabelHomeScreenSectionValue', i));
}
options.element.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
options.element.querySelector('.viewOrderList').addEventListener('click', onSectionOrderListClick);
options.element.querySelector('form').addEventListener('submit', onSubmit.bind(self));
options.element.addEventListener('change', onChange);
if (options.enableSaveButton) {
options.element.querySelector('.btnSave').classList.remove('hide');
}
if (layoutManager.tv) {
options.element.querySelector('.selectTVHomeScreenContainer').classList.remove('hide');
} else {
options.element.querySelector('.selectTVHomeScreenContainer').classList.add('hide');
}
self.loadData(options.autoFocus);
});
}
function HomeScreenSettings(options) {
this.options = options, embed(options, this)
this.options = options;
embed(options, this);
}
var numConfigurableSections = 7;
return HomeScreenSettings.prototype.loadData = function(autoFocus) {
var self = this,
context = self.options.element;
HomeScreenSettings.prototype.loadData = function (autoFocus) {
var self = this;
var context = self.options.element;
loading.show();
var userId = self.options.userId,
apiClient = connectionManager.getApiClient(self.options.serverId),
userSettings = self.options.userSettings;
apiClient.getUser(userId).then(function(user) {
userSettings.setUserInfo(userId, apiClient).then(function() {
self.dataLoaded = !0, loadForm(context, user, userSettings, apiClient), autoFocus && focusManager.autoFocus(context)
})
})
}, HomeScreenSettings.prototype.submit = function() {
onSubmit.call(this)
}, HomeScreenSettings.prototype.destroy = function() {
this.options = null
}, HomeScreenSettings
var userId = self.options.userId;
var apiClient = connectionManager.getApiClient(self.options.serverId);
var userSettings = self.options.userSettings;
apiClient.getUser(userId).then(function (user) {
userSettings.setUserInfo(userId, apiClient).then(function () {
self.dataLoaded = true;
loadForm(context, user, userSettings, apiClient);
if (autoFocus) {
focusManager.autoFocus(context);
}
});
});
};
HomeScreenSettings.prototype.submit = function () {
onSubmit.call(this);
};
HomeScreenSettings.prototype.destroy = function () {
this.options = null;
};
return HomeScreenSettings;
});
@@ -1,47 +1,88 @@
define(["dialogHelper", "layoutManager", "globalize", "require", "events", "homescreenSettings", "paper-icon-button-light", "css!./../formdialog"], function(dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) {
"use strict";
define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'events', 'homescreenSettings', 'paper-icon-button-light', 'css!./../formdialog'], function (dialogHelper, layoutManager, globalize, require, events, HomescreenSettings) {
'use strict';
function centerFocus(elem, horiz, on) {
require(["scrollHelper"], function(scrollHelper) {
var fn = on ? "on" : "off";
scrollHelper.centerFocus[fn](elem, horiz)
})
require(['scrollHelper'], function (scrollHelper) {
var fn = on ? 'on' : 'off';
scrollHelper.centerFocus[fn](elem, horiz);
});
}
function show(options) {
return new Promise(function(resolve, reject) {
require(["text!./homescreensettingsdialog.template.html"], function(template) {
return new Promise(function (resolve, reject) {
require(['text!./homescreensettingsdialog.template.html'], function (template) {
var dialogOptions = {
removeOnClose: !0,
scrollY: !1
removeOnClose: true,
scrollY: false
};
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "medium-tall";
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'medium-tall';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog");
var html = "",
submitted = !1;
html += globalize.translateDocument(template, "sharedcomponents"), dlg.innerHTML = html, layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !0);
dlg.classList.add('formDialog');
var html = '';
var submitted = false;
html += globalize.translateDocument(template, 'sharedcomponents');
dlg.innerHTML = html;
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, true);
}
var homescreenSettingsInstance = new HomescreenSettings({
serverId: options.serverId,
userId: options.userId,
element: dlg.querySelector(".settingsContent"),
element: dlg.querySelector('.settingsContent'),
userSettings: options.userSettings,
enableSaveButton: !1,
enableSaveConfirmation: !1
enableSaveButton: false,
enableSaveConfirmation: false
});
dialogHelper.open(dlg), dlg.addEventListener("close", function() {
layoutManager.tv && centerFocus(dlg.querySelector(".formDialogContent"), !1, !1), submitted ? resolve() : reject()
}), dlg.querySelector(".btnCancel").addEventListener("click", function(e) {
dialogHelper.close(dlg)
}), dlg.querySelector(".btnSave").addEventListener("click", function(e) {
submitted = !0, homescreenSettingsInstance.submit()
}), events.on(homescreenSettingsInstance, "saved", function() {
submitted = !0, dialogHelper.close(dlg)
})
})
})
dialogHelper.open(dlg);
dlg.addEventListener('close', function () {
if (layoutManager.tv) {
centerFocus(dlg.querySelector('.formDialogContent'), false, false);
}
if (submitted) {
resolve();
} else {
reject();
}
});
dlg.querySelector('.btnCancel').addEventListener('click', function (e) {
dialogHelper.close(dlg);
});
dlg.querySelector('.btnSave').addEventListener('click', function (e) {
submitted = true;
homescreenSettingsInstance.submit();
});
events.on(homescreenSettingsInstance, 'saved', function () {
submitted = true;
dialogHelper.close(dlg);
});
});
});
}
return {
show: show
}
};
});
@@ -1,10 +1,11 @@
.homeLibraryButton {
.homeLibraryButton {
min-width: 18%;
margin: .5em !important
margin: .5em !important;
}
@media all and (max-width:50em) {
@media all and (max-width: 50em) {
.homeLibraryButton {
width: 46% !important
width: 46% !important;
}
}
File diff suppressed because it is too large Load Diff
@@ -1,218 +1,515 @@
define(["events", "browser", "require", "apphost", "appSettings", "htmlMediaHelper"], function(events, browser, require, appHost, appSettings, htmlMediaHelper) {
define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelper'], function (events, browser, require, appHost, appSettings, htmlMediaHelper) {
"use strict";
function getDefaultProfile() {
return new Promise(function(resolve, reject) {
require(["browserdeviceprofile"], function(profileBuilder) {
resolve(profileBuilder({}))
})
})
return new Promise(function (resolve, reject) {
require(['browserdeviceprofile'], function (profileBuilder) {
resolve(profileBuilder({}));
});
});
}
var fadeTimeout;
function fade(instance, elem, startingVolume) {
instance._isFadingOut = !0;
var newVolume = Math.max(0, startingVolume - .15);
return console.log("fading volume to " + newVolume), elem.volume = newVolume, newVolume <= 0 ? (instance._isFadingOut = !1, Promise.resolve()) : new Promise(function(resolve, reject) {
cancelFadeTimeout(), fadeTimeout = setTimeout(function() {
fade(instance, elem, newVolume).then(resolve, reject)
}, 100)
})
instance._isFadingOut = true;
// Need to record the starting volume on each pass rather than querying elem.volume
// This is due to iOS safari not allowing volume changes and always returning the system volume value
var newVolume = Math.max(0, startingVolume - 0.15);
console.log('fading volume to ' + newVolume);
elem.volume = newVolume;
if (newVolume <= 0) {
instance._isFadingOut = false;
return Promise.resolve();
}
return new Promise(function (resolve, reject) {
cancelFadeTimeout();
fadeTimeout = setTimeout(function () {
fade(instance, elem, newVolume).then(resolve, reject);
}, 100);
});
}
function cancelFadeTimeout() {
var timeout = fadeTimeout;
timeout && (clearTimeout(timeout), fadeTimeout = null)
if (timeout) {
clearTimeout(timeout);
fadeTimeout = null;
}
}
function supportsFade() {
return !browser.tv
if (browser.tv) {
// Not working on tizen.
// We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
return false;
}
return true;
}
function requireHlsPlayer(callback) {
require(["hlsjs"], function(hls) {
window.Hls = hls, callback()
})
require(['hlsjs'], function (hls) {
window.Hls = hls;
callback();
});
}
function enableHlsPlayer(url, item, mediaSource, mediaType) {
return htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType) ? -1 !== url.indexOf(".m3u8") ? Promise.resolve() : new Promise(function(resolve, reject) {
require(["fetchHelper"], function(fetchHelper) {
if (!htmlMediaHelper.enableHlsJsPlayer(mediaSource.RunTimeTicks, mediaType)) {
return Promise.reject();
}
if (url.indexOf('.m3u8') !== -1) {
return Promise.resolve();
}
// issue head request to get content type
return new Promise(function (resolve, reject) {
require(['fetchHelper'], function (fetchHelper) {
fetchHelper.ajax({
url: url,
type: "HEAD"
}).then(function(response) {
"application/x-mpegurl" === (response.headers.get("Content-Type") || "").toLowerCase() ? resolve() : reject()
}, reject)
})
}) : Promise.reject()
type: 'HEAD'
}).then(function (response) {
var contentType = (response.headers.get('Content-Type') || '').toLowerCase();
if (contentType === 'application/x-mpegurl') {
resolve();
} else {
reject();
}
}, reject);
});
});
}
function HtmlAudioPlayer() {
var self = this;
self.name = 'Html Audio Player';
self.type = 'mediaplayer';
self.id = 'htmlaudioplayer';
// Let any players created by plugins take priority
self.priority = 1;
self.play = function (options) {
self._started = false;
self._timeUpdated = false;
self._currentTime = null;
var elem = createMediaElement(options);
return setCurrentSrc(elem, options);
};
function setCurrentSrc(elem, options) {
elem.removeEventListener("error", onError), unBindEvents(elem), bindEvents(elem);
elem.removeEventListener('error', onError);
unBindEvents(elem);
bindEvents(elem);
var val = options.url;
console.log("playing url: " + val);
var seconds = (options.playerStartPositionTicks || 0) / 1e7;
seconds && (val += "#t=" + seconds), htmlMediaHelper.destroyHlsPlayer(self), self._currentPlayOptions = options;
console.log('playing url: ' + val);
// Convert to seconds
var seconds = (options.playerStartPositionTicks || 0) / 10000000;
if (seconds) {
val += '#t=' + seconds;
}
htmlMediaHelper.destroyHlsPlayer(self);
self._currentPlayOptions = options;
var crossOrigin = htmlMediaHelper.getCrossOriginValue(options.mediaSource);
return crossOrigin && (elem.crossOrigin = crossOrigin), enableHlsPlayer(val, options.item, options.mediaSource, "Audio").then(function() {
return new Promise(function(resolve, reject) {
requireHlsPlayer(function() {
if (crossOrigin) {
elem.crossOrigin = crossOrigin;
}
return enableHlsPlayer(val, options.item, options.mediaSource, 'Audio').then(function () {
return new Promise(function (resolve, reject) {
requireHlsPlayer(function () {
var hls = new Hls({
manifestLoadingTimeOut: 2e4
manifestLoadingTimeOut: 20000
//appendErrorMaxRetry: 6,
//debug: true
});
hls.loadSource(val), hls.attachMedia(elem), htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject), self._hlsPlayer = hls, self._currentSrc = val
})
})
}, function() {
return elem.autoplay = !0, htmlMediaHelper.applySrc(elem, val, options).then(function() {
return self._currentSrc = val, htmlMediaHelper.playWithPromise(elem, onError)
})
})
hls.loadSource(val);
hls.attachMedia(elem);
htmlMediaHelper.bindEventsToHlsPlayer(self, hls, elem, onError, resolve, reject);
self._hlsPlayer = hls;
self._currentSrc = val;
});
});
}, function () {
elem.autoplay = true;
return htmlMediaHelper.applySrc(elem, val, options).then(function () {
self._currentSrc = val;
return htmlMediaHelper.playWithPromise(elem, onError);
});
});
}
function bindEvents(elem) {
elem.addEventListener("timeupdate", onTimeUpdate), elem.addEventListener("ended", onEnded), elem.addEventListener("volumechange", onVolumeChange), elem.addEventListener("pause", onPause), elem.addEventListener("playing", onPlaying), elem.addEventListener("play", onPlay)
elem.addEventListener('timeupdate', onTimeUpdate);
elem.addEventListener('ended', onEnded);
elem.addEventListener('volumechange', onVolumeChange);
elem.addEventListener('pause', onPause);
elem.addEventListener('playing', onPlaying);
elem.addEventListener('play', onPlay);
}
function unBindEvents(elem) {
elem.removeEventListener("timeupdate", onTimeUpdate), elem.removeEventListener("ended", onEnded), elem.removeEventListener("volumechange", onVolumeChange), elem.removeEventListener("pause", onPause), elem.removeEventListener("playing", onPlaying), elem.removeEventListener("play", onPlay)
elem.removeEventListener('timeupdate', onTimeUpdate);
elem.removeEventListener('ended', onEnded);
elem.removeEventListener('volumechange', onVolumeChange);
elem.removeEventListener('pause', onPause);
elem.removeEventListener('playing', onPlaying);
elem.removeEventListener('play', onPlay);
}
function createMediaElement() {
self.stop = function (destroyPlayer) {
cancelFadeTimeout();
var elem = self._mediaElement;
return elem || (elem = document.querySelector(".mediaPlayerAudio"), elem || (elem = document.createElement("audio"), elem.classList.add("mediaPlayerAudio"), elem.classList.add("hide"), document.body.appendChild(elem)), elem.volume = htmlMediaHelper.getSavedVolume(), self._mediaElement = elem, elem)
var src = self._currentSrc;
if (elem && src) {
if (!destroyPlayer || !supportsFade()) {
elem.pause();
htmlMediaHelper.onEndedInternal(self, elem, onError);
if (destroyPlayer) {
self.destroy();
}
return Promise.resolve();
}
var originalVolume = elem.volume;
return fade(self, elem, elem.volume).then(function () {
elem.pause();
elem.volume = originalVolume;
htmlMediaHelper.onEndedInternal(self, elem, onError);
if (destroyPlayer) {
self.destroy();
}
});
}
return Promise.resolve();
};
self.destroy = function () {
unBindEvents(self._mediaElement);
};
function createMediaElement() {
var elem = self._mediaElement;
if (elem) {
return elem;
}
elem = document.querySelector('.mediaPlayerAudio');
if (!elem) {
elem = document.createElement('audio');
elem.classList.add('mediaPlayerAudio');
elem.classList.add('hide');
document.body.appendChild(elem);
}
elem.volume = htmlMediaHelper.getSavedVolume();
self._mediaElement = elem;
return elem;
}
function onEnded() {
htmlMediaHelper.onEndedInternal(self, this, onError)
htmlMediaHelper.onEndedInternal(self, this, onError);
}
function onTimeUpdate() {
// Get the player position + the transcoding offset
var time = this.currentTime;
self._isFadingOut || (self._currentTime = time, events.trigger(self, "timeupdate"))
// Don't trigger events after user stop
if (!self._isFadingOut) {
self._currentTime = time;
events.trigger(self, 'timeupdate');
}
}
function onVolumeChange() {
self._isFadingOut || (htmlMediaHelper.saveVolume(this.volume), events.trigger(self, "volumechange"))
if (!self._isFadingOut) {
htmlMediaHelper.saveVolume(this.volume);
events.trigger(self, 'volumechange');
}
}
function onPlaying(e) {
self._started || (self._started = !0, this.removeAttribute("controls"), htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks)), events.trigger(self, "playing")
if (!self._started) {
self._started = true;
this.removeAttribute('controls');
htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks);
}
events.trigger(self, 'playing');
}
function onPlay(e) {
events.trigger(self, "unpause")
events.trigger(self, 'unpause');
}
function onPause() {
events.trigger(self, "pause")
events.trigger(self, 'pause');
}
function onError() {
var errorCode = this.error ? this.error.code || 0 : 0,
errorMessage = this.error ? this.error.message || "" : "";
console.log("Media element error: " + errorCode.toString() + " " + errorMessage);
var errorCode = this.error ? (this.error.code || 0) : 0;
var errorMessage = this.error ? (this.error.message || '') : '';
console.log('Media element error: ' + errorCode.toString() + ' ' + errorMessage);
var type;
switch (errorCode) {
case 1:
// MEDIA_ERR_ABORTED
// This will trigger when changing media while something is playing
return;
case 2:
type = "network";
// MEDIA_ERR_NETWORK
type = 'network';
break;
case 3:
if (self._hlsPlayer) return void htmlMediaHelper.handleHlsJsMediaError(self);
type = "mediadecodeerror";
// MEDIA_ERR_DECODE
if (self._hlsPlayer) {
htmlMediaHelper.handleHlsJsMediaError(self);
return;
} else {
type = 'mediadecodeerror';
}
break;
case 4:
type = "medianotsupported";
// MEDIA_ERR_SRC_NOT_SUPPORTED
type = 'medianotsupported';
break;
default:
return
// seeing cases where Edge is firing error events with no error code
// example is start playing something, then immediately change src to something else
return;
}
htmlMediaHelper.onErrorInternal(self, type)
}
var self = this;
self.name = "Html Audio Player", self.type = "mediaplayer", self.id = "htmlaudioplayer", self.priority = 1, self.play = function(options) {
return self._started = !1, self._timeUpdated = !1, self._currentTime = null, setCurrentSrc(createMediaElement(), options)
}, self.stop = function(destroyPlayer) {
cancelFadeTimeout();
var elem = self._mediaElement,
src = self._currentSrc;
if (elem && src) {
if (!destroyPlayer || !supportsFade()) return elem.pause(), htmlMediaHelper.onEndedInternal(self, elem, onError), destroyPlayer && self.destroy(), Promise.resolve();
var originalVolume = elem.volume;
return fade(self, elem, elem.volume).then(function() {
elem.pause(), elem.volume = originalVolume, htmlMediaHelper.onEndedInternal(self, elem, onError), destroyPlayer && self.destroy()
})
}
return Promise.resolve()
}, self.destroy = function() {
unBindEvents(self._mediaElement)
htmlMediaHelper.onErrorInternal(self, type);
}
}
var fadeTimeout;
return HtmlAudioPlayer.prototype.currentSrc = function() {
return this._currentSrc
}, HtmlAudioPlayer.prototype.canPlayMediaType = function(mediaType) {
return "audio" === (mediaType || "").toLowerCase()
}, HtmlAudioPlayer.prototype.getDeviceProfile = function(item) {
return appHost.getDeviceProfile ? appHost.getDeviceProfile(item) : getDefaultProfile()
}, HtmlAudioPlayer.prototype.currentTime = function(val) {
HtmlAudioPlayer.prototype.currentSrc = function () {
return this._currentSrc;
};
HtmlAudioPlayer.prototype.canPlayMediaType = function (mediaType) {
return (mediaType || '').toLowerCase() === 'audio';
};
HtmlAudioPlayer.prototype.getDeviceProfile = function (item) {
if (appHost.getDeviceProfile) {
return appHost.getDeviceProfile(item);
}
return getDefaultProfile();
};
// Save this for when playback stops, because querying the time at that point might return 0
HtmlAudioPlayer.prototype.currentTime = function (val) {
var mediaElement = this._mediaElement;
if (mediaElement) {
if (null != val) return void(mediaElement.currentTime = val / 1e3);
if (val != null) {
mediaElement.currentTime = val / 1000;
return;
}
var currentTime = this._currentTime;
return currentTime ? 1e3 * currentTime : 1e3 * (mediaElement.currentTime || 0)
if (currentTime) {
return currentTime * 1000;
}
return (mediaElement.currentTime || 0) * 1000;
}
}, HtmlAudioPlayer.prototype.duration = function(val) {
};
HtmlAudioPlayer.prototype.duration = function (val) {
var mediaElement = this._mediaElement;
if (mediaElement) {
var duration = mediaElement.duration;
if (htmlMediaHelper.isValidDuration(duration)) return 1e3 * duration
if (htmlMediaHelper.isValidDuration(duration)) {
return duration * 1000;
}
}
return null
}, HtmlAudioPlayer.prototype.seekable = function() {
return null;
};
HtmlAudioPlayer.prototype.seekable = function () {
var mediaElement = this._mediaElement;
if (mediaElement) {
var seekable = mediaElement.seekable;
if (seekable && seekable.length) {
var start = seekable.start(0),
end = seekable.end(0);
return htmlMediaHelper.isValidDuration(start) || (start = 0), htmlMediaHelper.isValidDuration(end) || (end = 0), end - start > 0
var start = seekable.start(0);
var end = seekable.end(0);
if (!htmlMediaHelper.isValidDuration(start)) {
start = 0;
}
if (!htmlMediaHelper.isValidDuration(end)) {
end = 0;
}
return (end - start) > 0;
}
return !1
return false;
}
}, HtmlAudioPlayer.prototype.getBufferedRanges = function() {
};
HtmlAudioPlayer.prototype.getBufferedRanges = function () {
var mediaElement = this._mediaElement;
return mediaElement ? htmlMediaHelper.getBufferedRanges(this, mediaElement) : []
}, HtmlAudioPlayer.prototype.pause = function() {
if (mediaElement) {
return htmlMediaHelper.getBufferedRanges(this, mediaElement);
}
return [];
};
HtmlAudioPlayer.prototype.pause = function () {
var mediaElement = this._mediaElement;
mediaElement && mediaElement.pause()
}, HtmlAudioPlayer.prototype.resume = function() {
if (mediaElement) {
mediaElement.pause();
}
};
// This is a retry after error
HtmlAudioPlayer.prototype.resume = function () {
var mediaElement = this._mediaElement;
mediaElement && mediaElement.play()
}, HtmlAudioPlayer.prototype.unpause = function() {
if (mediaElement) {
mediaElement.play();
}
};
HtmlAudioPlayer.prototype.unpause = function () {
var mediaElement = this._mediaElement;
mediaElement && mediaElement.play()
}, HtmlAudioPlayer.prototype.paused = function() {
if (mediaElement) {
mediaElement.play();
}
};
HtmlAudioPlayer.prototype.paused = function () {
var mediaElement = this._mediaElement;
return !!mediaElement && mediaElement.paused
}, HtmlAudioPlayer.prototype.setVolume = function(val) {
if (mediaElement) {
return mediaElement.paused;
}
return false;
};
HtmlAudioPlayer.prototype.setVolume = function (val) {
var mediaElement = this._mediaElement;
mediaElement && (mediaElement.volume = val / 100)
}, HtmlAudioPlayer.prototype.getVolume = function() {
if (mediaElement) {
mediaElement.volume = val / 100;
}
};
HtmlAudioPlayer.prototype.getVolume = function () {
var mediaElement = this._mediaElement;
if (mediaElement) return Math.min(Math.round(100 * mediaElement.volume), 100)
}, HtmlAudioPlayer.prototype.volumeUp = function() {
this.setVolume(Math.min(this.getVolume() + 2, 100))
}, HtmlAudioPlayer.prototype.volumeDown = function() {
this.setVolume(Math.max(this.getVolume() - 2, 0))
}, HtmlAudioPlayer.prototype.setMute = function(mute) {
if (mediaElement) {
return Math.min(Math.round(mediaElement.volume * 100), 100);
}
};
HtmlAudioPlayer.prototype.volumeUp = function () {
this.setVolume(Math.min(this.getVolume() + 2, 100));
};
HtmlAudioPlayer.prototype.volumeDown = function () {
this.setVolume(Math.max(this.getVolume() - 2, 0));
};
HtmlAudioPlayer.prototype.setMute = function (mute) {
var mediaElement = this._mediaElement;
mediaElement && (mediaElement.muted = mute)
}, HtmlAudioPlayer.prototype.isMuted = function() {
if (mediaElement) {
mediaElement.muted = mute;
}
};
HtmlAudioPlayer.prototype.isMuted = function () {
var mediaElement = this._mediaElement;
return !!mediaElement && mediaElement.muted
}, HtmlAudioPlayer.prototype.destroy = function() {}, HtmlAudioPlayer
if (mediaElement) {
return mediaElement.muted;
}
return false;
};
HtmlAudioPlayer.prototype.destroy = function () {
};
return HtmlAudioPlayer;
});
@@ -1,113 +1,254 @@
define(["appSettings", "browser", "events"], function(appSettings, browser, events) {
"use strict";
define(['appSettings', 'browser', 'events'], function (appSettings, browser, events) {
'use strict';
function getSavedVolume() {
return appSettings.get("volume") || 1
return appSettings.get("volume") || 1;
}
function saveVolume(value) {
value && appSettings.set("volume", value)
if (value) {
appSettings.set("volume", value);
}
}
function getCrossOriginValue(mediaSource) {
return mediaSource.IsRemote ? null : "anonymous"
if (mediaSource.IsRemote) {
return null;
}
return 'anonymous';
}
function canPlayNativeHls() {
var media = document.createElement("video");
return !(!media.canPlayType("application/x-mpegURL").replace(/no/, "") && !media.canPlayType("application/vnd.apple.mpegURL").replace(/no/, ""))
var media = document.createElement('video');
if (media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) {
return true;
}
return false;
}
function enableHlsShakaPlayer(item, mediaSource, mediaType) {
if (window.MediaSource && MediaSource.isTypeSupported) {
if (!!window.MediaSource && !!MediaSource.isTypeSupported) {
if (canPlayNativeHls()) {
if (browser.edge && "Video" === mediaType) return !0;
mediaSource.RunTimeTicks
if (browser.edge && mediaType === 'Video') {
return true;
}
// simple playback should use the native support
if (mediaSource.RunTimeTicks) {
//if (!browser.edge) {
//return false;
//}
}
//return false;
}
return !0
return true;
}
return !1
return false;
}
function enableHlsJsPlayer(runTimeTicks, mediaType) {
if (null == window.MediaSource) return !1;
if (browser.iOS) return !1;
if (browser.tizen || browser.web0s) return !1;
if (canPlayNativeHls()) {
if (browser.android && "Audio" === mediaType) return !0;
if (browser.edge, runTimeTicks) return !1
if (window.MediaSource == null) {
return false;
}
return !0
// hls.js is only in beta. needs more testing.
if (browser.iOS) {
return false;
}
// The native players on these devices support seeking live streams, no need to use hls.js here
if (browser.tizen || browser.web0s) {
return false;
}
if (canPlayNativeHls()) {
// Having trouble with chrome's native support and transcoded music
if (browser.android && mediaType === 'Audio') {
return true;
}
if (browser.edge && mediaType === 'Video') {
//return true;
}
// simple playback should use the native support
if (runTimeTicks) {
//if (!browser.edge) {
return false;
//}
}
//return false;
}
return true;
}
var recoverDecodingErrorDate, recoverSwapAudioCodecDate;
function handleHlsJsMediaError(instance, reject) {
var hlsPlayer = instance._hlsPlayer;
if (hlsPlayer) {
var now = Date.now();
window.performance && window.performance.now && (now = performance.now()), !recoverDecodingErrorDate || now - recoverDecodingErrorDate > 3e3 ? (recoverDecodingErrorDate = now, console.log("try to recover media Error ..."), hlsPlayer.recoverMediaError()) : !recoverSwapAudioCodecDate || now - recoverSwapAudioCodecDate > 3e3 ? (recoverSwapAudioCodecDate = now, console.log("try to swap Audio Codec and recover media Error ..."), hlsPlayer.swapAudioCodec(), hlsPlayer.recoverMediaError()) : (console.error("cannot recover, last media error recovery failed ..."), reject ? reject() : onErrorInternal(instance, "mediadecodeerror"))
if (!hlsPlayer) {
return;
}
var now = Date.now();
if (window.performance && window.performance.now) {
now = performance.now();
}
if (!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) {
recoverDecodingErrorDate = now;
console.log('try to recover media Error ...');
hlsPlayer.recoverMediaError();
} else {
if (!recoverSwapAudioCodecDate || (now - recoverSwapAudioCodecDate) > 3000) {
recoverSwapAudioCodecDate = now;
console.log('try to swap Audio Codec and recover media Error ...');
hlsPlayer.swapAudioCodec();
hlsPlayer.recoverMediaError();
} else {
console.error('cannot recover, last media error recovery failed ...');
if (reject) {
reject();
} else {
onErrorInternal(instance, 'mediadecodeerror');
}
}
}
}
function onErrorInternal(instance, type) {
instance.destroyCustomTrack && instance.destroyCustomTrack(instance._mediaElement), events.trigger(instance, "error", [{
type: type
}])
// Needed for video
if (instance.destroyCustomTrack) {
instance.destroyCustomTrack(instance._mediaElement);
}
events.trigger(instance, 'error', [
{
type: type
}]);
}
function isValidDuration(duration) {
return !(!duration || isNaN(duration) || duration === Number.POSITIVE_INFINITY || duration === Number.NEGATIVE_INFINITY)
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
return true;
}
return false;
}
function setCurrentTimeIfNeeded(element, seconds, allowance) {
Math.abs((element.currentTime || 0) - seconds) >= allowance && (element.currentTime = seconds)
function setCurrentTimeIfNeeded(element, seconds) {
if (Math.abs(element.currentTime || 0, seconds) <= 1) {
element.currentTime = seconds;
}
}
function seekOnPlaybackStart(instance, element, ticks) {
var seconds = (ticks || 0) / 1e7;
var seconds = (ticks || 0) / 10000000;
if (seconds) {
(instance.currentSrc() || "").toLowerCase();
setCurrentTimeIfNeeded(element, seconds, 5), setTimeout(function() {
setCurrentTimeIfNeeded(element, seconds, 10)
}, 2500)
var src = (instance.currentSrc() || '').toLowerCase();
// Appending #t=xxx to the query string doesn't seem to work with HLS
// For plain video files, not all browsers support it either
var delay = browser.safari ? 2500 : 0;
if (delay) {
setTimeout(function () {
setCurrentTimeIfNeeded(element, seconds);
}, delay);
} else {
setCurrentTimeIfNeeded(element, seconds);
}
}
}
function applySrc(elem, src, options) {
return window.Windows && options.mediaSource && options.mediaSource.IsLocal ? Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function(file) {
var playlist = new Windows.Media.Playback.MediaPlaybackList,
source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file),
startTime = (options.playerStartPositionTicks || 0) / 1e4;
return playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime)), elem.src = URL.createObjectURL(playlist, {
oneTimeOnly: !0
}), Promise.resolve()
}) : (elem.src = src, Promise.resolve())
if (window.Windows && options.mediaSource && options.mediaSource.IsLocal) {
return Windows.Storage.StorageFile.getFileFromPathAsync(options.url).then(function (file) {
var playlist = new Windows.Media.Playback.MediaPlaybackList();
var source1 = Windows.Media.Core.MediaSource.createFromStorageFile(file);
var startTime = (options.playerStartPositionTicks || 0) / 10000;
playlist.items.append(new Windows.Media.Playback.MediaPlaybackItem(source1, startTime));
elem.src = URL.createObjectURL(playlist, { oneTimeOnly: true });
return Promise.resolve();
});
} else {
elem.src = src;
}
return Promise.resolve();
}
function onSuccessfulPlay(elem, onErrorFn) {
elem.addEventListener("error", onErrorFn)
elem.addEventListener('error', onErrorFn);
}
function playWithPromise(elem, onErrorFn) {
try {
var promise = elem.play();
return promise && promise.then ? promise.catch(function(e) {
var errorName = (e.name || "").toLowerCase();
return "notallowederror" === errorName || "aborterror" === errorName ? (onSuccessfulPlay(elem, onErrorFn), Promise.resolve()) : Promise.reject()
}) : (onSuccessfulPlay(elem, onErrorFn), Promise.resolve())
if (promise && promise.then) {
// Chrome now returns a promise
return promise.catch(function (e) {
var errorName = (e.name || '').toLowerCase();
// safari uses aborterror
if (errorName === 'notallowederror' ||
errorName === 'aborterror') {
// swallow this error because the user can still click the play button on the video element
onSuccessfulPlay(elem, onErrorFn);
return Promise.resolve();
}
return Promise.reject();
});
} else {
onSuccessfulPlay(elem, onErrorFn);
return Promise.resolve();
}
} catch (err) {
return console.log("error calling video.play: " + err), Promise.reject()
console.log('error calling video.play: ' + err);
return Promise.reject();
}
}
function destroyCastPlayer(instance) {
var player = instance._castPlayer;
if (player) {
try {
player.unload()
player.unload();
} catch (err) {
console.log(err)
console.log(err);
}
instance._castPlayer = null
instance._castPlayer = null;
}
}
@@ -115,11 +256,12 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
var player = instance._shakaPlayer;
if (player) {
try {
player.destroy()
player.destroy();
} catch (err) {
console.log(err)
console.log(err);
}
instance._shakaPlayer = null
instance._shakaPlayer = null;
}
}
@@ -127,11 +269,12 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
var player = instance._hlsPlayer;
if (player) {
try {
player.destroy()
player.destroy();
} catch (err) {
console.log(err)
console.log(err);
}
instance._hlsPlayer = null
instance._hlsPlayer = null;
}
}
@@ -139,63 +282,170 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
var player = instance._flvPlayer;
if (player) {
try {
player.unload(), player.detachMediaElement(), player.destroy()
player.unload();
player.detachMediaElement();
player.destroy();
} catch (err) {
console.log(err)
console.log(err);
}
instance._flvPlayer = null
instance._flvPlayer = null;
}
}
function bindEventsToHlsPlayer(instance, hls, elem, onErrorFn, resolve, reject) {
hls.on(Hls.Events.MANIFEST_PARSED, function() {
playWithPromise(elem, onErrorFn).then(resolve, function() {
reject && (reject(), reject = null)
})
}), hls.on(Hls.Events.ERROR, function(event, data) {
switch (console.log("HLS Error: Type: " + data.type + " Details: " + (data.details || "") + " Fatal: " + (data.fatal || !1)), data.type) {
hls.on(Hls.Events.MANIFEST_PARSED, function () {
playWithPromise(elem, onErrorFn).then(resolve, function () {
if (reject) {
reject();
reject = null;
}
});
});
hls.on(Hls.Events.ERROR, function (event, data) {
console.log('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false));
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
if (data.response && data.response.code && data.response.code >= 400) return console.log("hls.js response error code: " + data.response.code), hls.destroy(), void(reject ? (reject("servererror"), reject = null) : onErrorInternal(instance, "servererror"))
}
if (data.fatal) switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
data.response && 0 === data.response.code ? (console.log("hls.js response error code: " + data.response.code), hls.destroy(), reject ? (reject("network"), reject = null) : onErrorInternal(instance, "network")) : (console.log("fatal network error encountered, try to recover"), hls.startLoad());
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log("fatal media error encountered, try to recover");
var currentReject = reject;
reject = null, handleHlsJsMediaError(instance, currentReject);
// try to recover network error
if (data.response && data.response.code && data.response.code >= 400) {
console.log('hls.js response error code: ' + data.response.code);
// Trigger failure differently depending on whether this is prior to start of playback, or after
hls.destroy();
if (reject) {
reject('servererror');
reject = null;
} else {
onErrorInternal(instance, 'servererror');
}
return;
}
break;
default:
console.log("Cannot recover from hls error - destroy and trigger error"), hls.destroy(), reject ? (reject(), reject = null) : onErrorInternal(instance, "mediadecodeerror")
break;
}
})
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
if (data.response && data.response.code === 0) {
// This could be a CORS error related to access control response headers
console.log('hls.js response error code: ' + data.response.code);
// Trigger failure differently depending on whether this is prior to start of playback, or after
hls.destroy();
if (reject) {
reject('network');
reject = null;
} else {
onErrorInternal(instance, 'network');
}
}
else {
console.log("fatal network error encountered, try to recover");
hls.startLoad();
}
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.log("fatal media error encountered, try to recover");
var currentReject = reject;
reject = null;
handleHlsJsMediaError(instance, currentReject);
break;
default:
console.log('Cannot recover from hls error - destroy and trigger error');
// cannot recover
// Trigger failure differently depending on whether this is prior to start of playback, or after
hls.destroy();
if (reject) {
reject();
reject = null;
} else {
onErrorInternal(instance, 'mediadecodeerror');
}
break;
}
}
});
}
function onEndedInternal(instance, elem, onErrorFn) {
elem.removeEventListener("error", onErrorFn), elem.src = "", elem.innerHTML = "", elem.removeAttribute("src"), destroyHlsPlayer(instance), destroyFlvPlayer(instance), destroyShakaPlayer(instance), destroyCastPlayer(instance);
elem.removeEventListener('error', onErrorFn);
elem.src = '';
elem.innerHTML = '';
elem.removeAttribute("src");
destroyHlsPlayer(instance);
destroyFlvPlayer(instance);
destroyShakaPlayer(instance);
destroyCastPlayer(instance);
var stopInfo = {
src: instance._currentSrc
};
events.trigger(instance, "stopped", [stopInfo]), instance._currentTime = null, instance._currentSrc = null, instance._currentPlayOptions = null
events.trigger(instance, 'stopped', [stopInfo]);
instance._currentTime = null;
instance._currentSrc = null;
instance._currentPlayOptions = null;
}
function getBufferedRanges(instance, elem) {
var offset, ranges = [],
seekable = elem.buffered || [],
currentPlayOptions = instance._currentPlayOptions;
currentPlayOptions && (offset = currentPlayOptions.transcodingOffsetTicks), offset = offset || 0;
for (var i = 0, length = seekable.length; i < length; i++) {
var start = seekable.start(i),
end = seekable.end(i);
isValidDuration(start) || (start = 0), isValidDuration(end) ? ranges.push({
start: 1e7 * start + offset,
end: 1e7 * end + offset
}) : end = 0
var ranges = [];
var seekable = elem.buffered || [];
var offset;
var currentPlayOptions = instance._currentPlayOptions;
if (currentPlayOptions) {
offset = currentPlayOptions.transcodingOffsetTicks;
}
return ranges
offset = offset || 0;
for (var i = 0, length = seekable.length; i < length; i++) {
var start = seekable.start(i);
var end = seekable.end(i);
if (!isValidDuration(start)) {
start = 0;
}
if (!isValidDuration(end)) {
end = 0;
continue;
}
ranges.push({
start: (start * 10000000) + offset,
end: (end * 10000000) + offset
});
}
return ranges;
}
var recoverDecodingErrorDate, recoverSwapAudioCodecDate;
return {
getSavedVolume: getSavedVolume,
saveVolume: saveVolume,
@@ -214,5 +464,5 @@ define(["appSettings", "browser", "events"], function(appSettings, browser, even
onEndedInternal: onEndedInternal,
getCrossOriginValue: getCrossOriginValue,
getBufferedRanges: getBufferedRanges
}
};
});
File diff suppressed because it is too large Load Diff
@@ -4,47 +4,43 @@
bottom: 0;
left: 0;
right: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center
align-items: center;
}
.videoPlayerContainer:not(.videoPlayerContainer-withBackdrop) {
background: #000 !important
}
.videoPlayerContainer:not(.videoPlayerContainer-withBackdrop) {
background: #000 !important;
}
.videoPlayerContainer-withBackdrop {
background-repeat: no-repeat;
background-position: center center;
-webkit-background-size: cover;
background-size: cover;
background-attachment: fixed;
background-color: #000
background-color: #000;
}
.videoPlayerContainer-onTop {
z-index: 1000
z-index: 1000;
}
.htmlvideoplayer {
margin: 0 !important;
padding: 0 !important;
width: 100%;
height: 100%
height: 100%;
}
.htmlvideoplayer::cue {
background-color: transparent;
text-shadow: .14em .14em .14em rgba(0, 0, 0, 1);
-webkit-font-smoothing: antialiased;
font-family: inherit
}
.htmlvideoplayer::cue {
background-color: transparent;
text-shadow: .14em .14em .14em rgba(0, 0, 0, 1);
-webkit-font-smoothing: antialiased;
font-family: inherit;
}
.htmlvideoplayer-moveupsubtitles::-webkit-media-text-track-display {
margin-top: -2em
/*Style the text itself*/
margin-top: -2em;
}
.videoSubtitles {
@@ -54,41 +50,25 @@
left: 0;
right: 0;
color: #fff;
font-size: 170%
font-size: 170%;
}
.videoSubtitlesInner {
max-width: 70%;
background-color: rgba(0, 0, 0, .8);
background-color: rgba(0,0,0,.8);
padding: .25em;
margin: auto;
display: inline-block
}
@-webkit-keyframes htmlvideoplayer-zoomin {
from {
-webkit-transform: scale3d(.2, .2, .2);
transform: scale3d(.2, .2, .2);
opacity: .6
}
to {
-webkit-transform: none;
transform: none;
opacity: initial
}
display: inline-block;
}
@keyframes htmlvideoplayer-zoomin {
from {
-webkit-transform: scale3d(.2, .2, .2);
transform: scale3d(.2, .2, .2);
opacity: .6
opacity: .6;
}
to {
-webkit-transform: none;
transform: none;
opacity: initial
opacity: initial;
}
}
}
@@ -1,126 +1,416 @@
define(["loading", "apphost", "dialogHelper", "connectionManager", "imageLoader", "browser", "layoutManager", "scrollHelper", "globalize", "require", "emby-checkbox", "emby-button", "paper-icon-button-light", "emby-linkbutton", "formDialogStyle", "cardStyle"], function(loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) {
"use strict";
define(['loading', 'apphost', 'dialogHelper', 'connectionManager', 'imageLoader', 'browser', 'layoutManager', 'scrollHelper', 'globalize', 'require', 'emby-checkbox', 'emby-button', 'paper-icon-button-light', 'emby-linkbutton', 'formDialogStyle', 'cardStyle'], function (loading, appHost, dialogHelper, connectionManager, imageLoader, browser, layoutManager, scrollHelper, globalize, require) {
'use strict';
var currentItemId;
var currentItemType;
var currentResolve;
var currentReject;
var hasChanges = false;
// These images can be large and we're seeing memory problems in safari
var browsableImagePageSize = browser.slow ? 6 : 30;
var browsableImageStartIndex = 0;
var browsableImageType = 'Primary';
var selectedProvider;
function getBaseRemoteOptions() {
var options = {};
return options.itemId = currentItemId, options
options.itemId = currentItemId;
return options;
}
function reloadBrowsableImages(page, apiClient) {
loading.show();
var options = getBaseRemoteOptions();
options.type = browsableImageType, options.startIndex = browsableImageStartIndex, options.limit = browsableImagePageSize, options.IncludeAllLanguages = page.querySelector("#chkAllLanguages").checked;
var provider = selectedProvider || "";
provider && (options.ProviderName = provider), apiClient.getAvailableRemoteImages(options).then(function(result) {
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit), page.querySelector("#selectBrowsableImageType").value = browsableImageType;
var providersHtml = result.Providers.map(function(p) {
return '<option value="' + p + '">' + p + "</option>"
}),
selectImageProvider = page.querySelector("#selectImageProvider");
selectImageProvider.innerHTML = '<option value="">' + globalize.translate("sharedcomponents#All") + "</option>" + providersHtml, selectImageProvider.value = provider, loading.hide()
})
options.type = browsableImageType;
options.startIndex = browsableImageStartIndex;
options.limit = browsableImagePageSize;
options.IncludeAllLanguages = page.querySelector('#chkAllLanguages').checked;
var provider = selectedProvider || '';
if (provider) {
options.ProviderName = provider;
}
apiClient.getAvailableRemoteImages(options).then(function (result) {
renderRemoteImages(page, apiClient, result, browsableImageType, options.startIndex, options.limit);
page.querySelector('#selectBrowsableImageType').value = browsableImageType;
var providersHtml = result.Providers.map(function (p) {
return '<option value="' + p + '">' + p + '</option>';
});
var selectImageProvider = page.querySelector('#selectImageProvider');
selectImageProvider.innerHTML = '<option value="">' + globalize.translate('sharedcomponents#All') + '</option>' + providersHtml;
selectImageProvider.value = provider;
loading.hide();
});
}
function renderRemoteImages(page, apiClient, imagesResult, imageType, startIndex, limit) {
page.querySelector(".availableImagesPaging").innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
for (var html = "", i = 0, length = imagesResult.Images.length; i < length; i++) html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
var availableImagesList = page.querySelector(".availableImagesList");
availableImagesList.innerHTML = html, imageLoader.lazyChildren(availableImagesList);
var btnNextPage = page.querySelector(".btnNextPage"),
btnPreviousPage = page.querySelector(".btnPreviousPage");
btnNextPage && btnNextPage.addEventListener("click", function() {
browsableImageStartIndex += browsableImagePageSize, reloadBrowsableImages(page, apiClient)
}), btnPreviousPage && btnPreviousPage.addEventListener("click", function() {
browsableImageStartIndex -= browsableImagePageSize, reloadBrowsableImages(page, apiClient)
})
page.querySelector('.availableImagesPaging').innerHTML = getPagingHtml(startIndex, limit, imagesResult.TotalRecordCount);
var html = '';
for (var i = 0, length = imagesResult.Images.length; i < length; i++) {
html += getRemoteImageHtml(imagesResult.Images[i], imageType, apiClient);
}
var availableImagesList = page.querySelector('.availableImagesList');
availableImagesList.innerHTML = html;
imageLoader.lazyChildren(availableImagesList);
var btnNextPage = page.querySelector('.btnNextPage');
var btnPreviousPage = page.querySelector('.btnPreviousPage');
if (btnNextPage) {
btnNextPage.addEventListener('click', function () {
browsableImageStartIndex += browsableImagePageSize;
reloadBrowsableImages(page, apiClient);
});
}
if (btnPreviousPage) {
btnPreviousPage.addEventListener('click', function () {
browsableImageStartIndex -= browsableImagePageSize;
reloadBrowsableImages(page, apiClient);
});
}
}
function getPagingHtml(startIndex, limit, totalRecordCount) {
var html = "",
recordsEnd = Math.min(startIndex + limit, totalRecordCount),
showControls = totalRecordCount > limit;
return html += '<div class="listPaging">', html += '<span style="margin-right: 10px;">', html += (totalRecordCount ? startIndex + 1 : 0) + "-" + recordsEnd + " of " + totalRecordCount, html += "</span>", showControls && (html += '<div data-role="controlgroup" data-type="horizontal" style="display:inline-block;">', html += '<button is="paper-icon-button-light" title="' + globalize.translate("sharedcomponents#Previous") + '" class="btnPreviousPage autoSize" ' + (startIndex ? "" : "disabled") + '><i class="md-icon">&#xE5C4;</i></button>', html += '<button is="paper-icon-button-light" title="' + globalize.translate("sharedcomponents#Next") + '" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? "disabled" : "") + '><i class="md-icon">arrow_forward</i></button>', html += "</div>"), html += "</div>"
var html = '';
var recordsEnd = Math.min(startIndex + limit, totalRecordCount);
// 20 is the minimum page size
var showControls = totalRecordCount > limit;
html += '<div class="listPaging">';
html += '<span style="margin-right: 10px;">';
var startAtDisplay = totalRecordCount ? startIndex + 1 : 0;
html += startAtDisplay + '-' + recordsEnd + ' of ' + totalRecordCount;
html += '</span>';
if (showControls) {
html += '<div data-role="controlgroup" data-type="horizontal" style="display:inline-block;">';
html += '<button is="paper-icon-button-light" title="' + globalize.translate('sharedcomponents#Previous') + '" class="btnPreviousPage autoSize" ' + (startIndex ? '' : 'disabled') + '><i class="md-icon">&#xE5C4;</i></button>';
html += '<button is="paper-icon-button-light" title="' + globalize.translate('sharedcomponents#Next') + '" class="btnNextPage autoSize" ' + (startIndex + limit >= totalRecordCount ? 'disabled' : '') + '><i class="md-icon">arrow_forward</i></button>';
html += '</div>';
}
html += '</div>';
return html;
}
function parentWithClass(elem, className) {
for (; !elem.classList || !elem.classList.contains(className);)
if (!(elem = elem.parentNode)) return null;
return elem
while (!elem.classList || !elem.classList.contains(className)) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
}
function downloadRemoteImage(page, apiClient, url, type, provider) {
var options = getBaseRemoteOptions();
options.Type = type, options.ImageUrl = url, options.ProviderName = provider, loading.show(), apiClient.downloadRemoteImage(options).then(function() {
hasChanges = !0;
var dlg = parentWithClass(page, "dialog");
dialogHelper.close(dlg)
})
options.Type = type;
options.ImageUrl = url;
options.ProviderName = provider;
loading.show();
apiClient.downloadRemoteImage(options).then(function () {
hasChanges = true;
var dlg = parentWithClass(page, 'dialog');
dialogHelper.close(dlg);
});
}
function getDisplayUrl(url, apiClient) {
return apiClient.getUrl("Images/Remote", {
imageUrl: url
})
return apiClient.getUrl("Images/Remote", { imageUrl: url });
}
function getRemoteImageHtml(image, imageType, apiClient) {
var tagName = layoutManager.tv ? "button" : "div",
enableFooterButtons = !layoutManager.tv,
html = "",
cssClass = "card scalableCard imageEditorCard",
cardBoxCssClass = "cardBox visualCardBox",
shape = "backdrop";
return shape = "Backdrop" === imageType || "Art" === imageType || "Thumb" === imageType || "Logo" === imageType ? "backdrop" : "Banner" === imageType ? "banner" : "Disc" === imageType ? "square" : "Episode" === currentItemType ? "backdrop" : "MusicAlbum" === currentItemType || "MusicArtist" === currentItemType ? "square" : "portrait", cssClass += " " + shape + "Card " + shape + "Card-scalable", "button" === tagName ? (cssClass += " btnImageCard", layoutManager.tv && !browser.slow && (cardBoxCssClass += " cardBox-focustransform"), layoutManager.tv && (cardBoxCssClass += " card-focuscontent cardBox-withfocuscontent"), html += '<button type="button" class="' + cssClass + '"') : html += '<div class="' + cssClass + '"', html += ' data-imageprovider="' + image.ProviderName + '" data-imageurl="' + image.Url + '" data-imagetype="' + image.Type + '"', html += ">", html += '<div class="' + cardBoxCssClass + '">', html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">', html += '<div class="cardPadder-' + shape + '"></div>', html += '<div class="cardContent">', layoutManager.tv || !appHost.supports("externallinks") ? html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></div>' : html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></a>', html += "</div>", html += "</div>", html += '<div class="cardFooter visualCardBox-cardFooter">', html += '<div class="cardText cardTextCentered">' + image.ProviderName + "</div>", (image.Width || image.Height || image.Language) && (html += '<div class="cardText cardText-secondary cardTextCentered">', image.Width && image.Height ? (html += image.Width + " x " + image.Height, image.Language && (html += " • " + image.Language)) : image.Language && (html += image.Language), html += "</div>"), null != image.CommunityRating && (html += '<div class="cardText cardText-secondary cardTextCentered">', "Likes" === image.RatingType ? html += image.CommunityRating + (1 === image.CommunityRating ? " like" : " likes") : image.CommunityRating ? (html += image.CommunityRating.toFixed(1), image.VoteCount && (html += " • " + image.VoteCount + (1 === image.VoteCount ? " vote" : " votes"))) : html += "Unrated", html += "</div>"), enableFooterButtons && (html += '<div class="cardText cardTextCentered">', html += '<button is="paper-icon-button-light" class="btnDownloadRemoteImage autoSize" raised" title="' + globalize.translate("sharedcomponents#Download") + '"><i class="md-icon">&#xE2C0;</i></button>', html += "</div>"), html += "</div>", html += "</div>", html += "</" + tagName + ">"
var tagName = layoutManager.tv ? 'button' : 'div';
var enableFooterButtons = !layoutManager.tv;
var html = '';
var cssClass = "card scalableCard imageEditorCard";
var cardBoxCssClass = 'cardBox visualCardBox';
var shape = 'backdrop';
if (imageType === "Backdrop" || imageType === "Art" || imageType === "Thumb" || imageType === "Logo") {
shape = 'backdrop';
}
else if (imageType === "Banner") {
shape = 'banner';
}
else if (imageType === "Disc") {
shape = 'square';
}
else {
if (currentItemType === "Episode") {
shape = 'backdrop';
}
else if (currentItemType === "MusicAlbum" || currentItemType === "MusicArtist") {
shape = 'square';
}
else {
shape = 'portrait';
}
}
cssClass += ' ' + shape + 'Card ' + shape + 'Card-scalable';
if (tagName === 'button') {
cssClass += ' btnImageCard';
if (layoutManager.tv && !browser.slow) {
cardBoxCssClass += ' cardBox-focustransform';
}
if (layoutManager.tv) {
cardBoxCssClass += ' card-focuscontent cardBox-withfocuscontent';
}
html += '<button type="button" class="' + cssClass + '"';
} else {
html += '<div class="' + cssClass + '"';
}
html += ' data-imageprovider="' + image.ProviderName + '" data-imageurl="' + image.Url + '" data-imagetype="' + image.Type + '"';
html += '>';
html += '<div class="' + cardBoxCssClass + '">';
html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">';
html += '<div class="cardPadder-' + shape + '"></div>';
html += '<div class="cardContent">';
if (layoutManager.tv || !appHost.supports('externallinks')) {
html += '<div class="cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></div>';
}
else {
html += '<a is="emby-linkbutton" target="_blank" href="' + getDisplayUrl(image.Url, apiClient) + '" class="button-link cardImageContainer lazy" data-src="' + getDisplayUrl(image.Url, apiClient) + '" style="background-position:center bottom;"></a>';
}
html += '</div>';
html += '</div>';
// begin footer
html += '<div class="cardFooter visualCardBox-cardFooter">';
html += '<div class="cardText cardTextCentered">' + image.ProviderName + '</div>';
if (image.Width || image.Height || image.Language) {
html += '<div class="cardText cardText-secondary cardTextCentered">';
if (image.Width && image.Height) {
html += image.Width + ' x ' + image.Height;
if (image.Language) {
html += ' • ' + image.Language;
}
} else {
if (image.Language) {
html += image.Language;
}
}
html += '</div>';
}
if (image.CommunityRating != null) {
html += '<div class="cardText cardText-secondary cardTextCentered">';
if (image.RatingType === "Likes") {
html += image.CommunityRating + (image.CommunityRating === 1 ? " like" : " likes");
} else {
if (image.CommunityRating) {
html += image.CommunityRating.toFixed(1);
if (image.VoteCount) {
html += ' • ' + image.VoteCount + (image.VoteCount === 1 ? " vote" : " votes");
}
} else {
html += "Unrated";
}
}
html += '</div>';
}
if (enableFooterButtons) {
html += '<div class="cardText cardTextCentered">';
html += '<button is="paper-icon-button-light" class="btnDownloadRemoteImage autoSize" raised" title="' + globalize.translate('sharedcomponents#Download') + '"><i class="md-icon">&#xE2C0;</i></button>';
html += '</div>';
}
html += '</div>';
// end footer
html += '</div>';
//html += '</div>';
html += '</' + tagName + '>';
return html;
}
function initEditor(page, apiClient) {
page.querySelector("#selectBrowsableImageType").addEventListener("change", function() {
browsableImageType = this.value, browsableImageStartIndex = 0, selectedProvider = null, reloadBrowsableImages(page, apiClient)
}), page.querySelector("#selectImageProvider").addEventListener("change", function() {
browsableImageStartIndex = 0, selectedProvider = this.value, reloadBrowsableImages(page, apiClient)
}), page.querySelector("#chkAllLanguages").addEventListener("change", function() {
browsableImageStartIndex = 0, reloadBrowsableImages(page, apiClient)
}), page.addEventListener("click", function(e) {
var btnDownloadRemoteImage = parentWithClass(e.target, "btnDownloadRemoteImage");
page.querySelector('#selectBrowsableImageType').addEventListener('change', function () {
browsableImageType = this.value;
browsableImageStartIndex = 0;
selectedProvider = null;
reloadBrowsableImages(page, apiClient);
});
page.querySelector('#selectImageProvider').addEventListener('change', function () {
browsableImageStartIndex = 0;
selectedProvider = this.value;
reloadBrowsableImages(page, apiClient);
});
page.querySelector('#chkAllLanguages').addEventListener('change', function () {
browsableImageStartIndex = 0;
reloadBrowsableImages(page, apiClient);
});
page.addEventListener('click', function (e) {
var btnDownloadRemoteImage = parentWithClass(e.target, 'btnDownloadRemoteImage');
if (btnDownloadRemoteImage) {
var card = parentWithClass(btnDownloadRemoteImage, "card");
return void downloadRemoteImage(page, apiClient, card.getAttribute("data-imageurl"), card.getAttribute("data-imagetype"), card.getAttribute("data-imageprovider"))
var card = parentWithClass(btnDownloadRemoteImage, 'card');
downloadRemoteImage(page, apiClient, card.getAttribute('data-imageurl'), card.getAttribute('data-imagetype'), card.getAttribute('data-imageprovider'));
return;
}
var btnImageCard = parentWithClass(e.target, "btnImageCard");
btnImageCard && downloadRemoteImage(page, apiClient, btnImageCard.getAttribute("data-imageurl"), btnImageCard.getAttribute("data-imagetype"), btnImageCard.getAttribute("data-imageprovider"))
})
var btnImageCard = parentWithClass(e.target, 'btnImageCard');
if (btnImageCard) {
downloadRemoteImage(page, apiClient, btnImageCard.getAttribute('data-imageurl'), btnImageCard.getAttribute('data-imagetype'), btnImageCard.getAttribute('data-imageprovider'));
}
});
}
function showEditor(itemId, serverId, itemType) {
loading.show(), require(["text!./imagedownloader.template.html"], function(template) {
loading.show();
require(['text!./imagedownloader.template.html'], function (template) {
var apiClient = connectionManager.getApiClient(serverId);
currentItemId = itemId, currentItemType = itemType;
currentItemId = itemId;
currentItemType = itemType;
var dialogOptions = {
removeOnClose: !0
removeOnClose: true
};
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border";
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'fullscreen-border';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), dlg.addEventListener("close", onDialogClosed), dialogHelper.open(dlg);
var editorContent = dlg.querySelector(".formDialogContent");
initEditor(editorContent, apiClient), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg)
}), reloadBrowsableImages(editorContent, apiClient)
})
dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg, false);
}
// Has to be assigned a z-index after the call to .open()
dlg.addEventListener('close', onDialogClosed);
dialogHelper.open(dlg);
var editorContent = dlg.querySelector('.formDialogContent');
initEditor(editorContent, apiClient);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
reloadBrowsableImages(editorContent, apiClient);
});
}
function onDialogClosed() {
var dlg = this;
layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), hasChanges ? currentResolve() : currentReject()
}
var currentItemId, currentItemType, currentResolve, currentReject, selectedProvider, hasChanges = !1,
browsableImagePageSize = browser.slow ? 6 : 30,
browsableImageStartIndex = 0,
browsableImageType = "Primary";
return {
show: function(itemId, serverId, itemType, imageType) {
return new Promise(function(resolve, reject) {
currentResolve = resolve, currentReject = reject, hasChanges = !1, browsableImageStartIndex = 0, browsableImageType = imageType || "Primary", selectedProvider = null, showEditor(itemId, serverId, itemType)
})
if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg, false);
}
loading.hide();
if (hasChanges) {
currentResolve();
} else {
currentReject();
}
}
return {
show: function (itemId, serverId, itemType, imageType) {
return new Promise(function (resolve, reject) {
currentResolve = resolve;
currentReject = reject;
hasChanges = false;
browsableImageStartIndex = 0;
browsableImageType = imageType || 'Primary';
selectedProvider = null;
showEditor(itemId, serverId, itemType);
});
}
};
});
@@ -1,13 +1,9 @@
.imageEditor-buttons {
display: -webkit-box;
display: -webkit-flex;
.imageEditor-buttons {
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
margin: 1em 0
margin: 1em 0 1em;
}
.first-imageEditor-buttons {
margin-top: 2em
margin-top: 2em;
}
@@ -1,220 +1,513 @@
define(["dialogHelper", "connectionManager", "loading", "dom", "layoutManager", "focusManager", "globalize", "scrollHelper", "imageLoader", "require", "browser", "apphost", "cardStyle", "formDialogStyle", "emby-button", "paper-icon-button-light", "css!./imageeditor"], function(dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) {
"use strict";
define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager', 'focusManager', 'globalize', 'scrollHelper', 'imageLoader', 'require', 'browser', 'apphost', 'cardStyle', 'formDialogStyle', 'emby-button', 'paper-icon-button-light', 'css!./imageeditor'], function (dialogHelper, connectionManager, loading, dom, layoutManager, focusManager, globalize, scrollHelper, imageLoader, require, browser, appHost) {
'use strict';
var currentItem;
var hasChanges = false;
function getBaseRemoteOptions() {
var options = {};
return options.itemId = currentItem.Id, options
options.itemId = currentItem.Id;
return options;
}
function reload(page, item, focusContext) {
loading.show();
var apiClient;
item ? (apiClient = connectionManager.getApiClient(item.ServerId), reloadItem(page, item, apiClient, focusContext)) : (apiClient = connectionManager.getApiClient(currentItem.ServerId), apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function(item) {
reloadItem(page, item, apiClient, focusContext)
}))
if (item) {
apiClient = connectionManager.getApiClient(item.ServerId);
reloadItem(page, item, apiClient, focusContext);
}
else {
apiClient = connectionManager.getApiClient(currentItem.ServerId);
apiClient.getItem(apiClient.getCurrentUserId(), currentItem.Id).then(function (item) {
reloadItem(page, item, apiClient, focusContext);
});
}
}
function addListeners(container, className, eventName, fn) {
container.addEventListener(eventName, function(e) {
container.addEventListener(eventName, function (e) {
var elem = dom.parentWithClass(e.target, className);
elem && fn.call(elem, e)
})
if (elem) {
fn.call(elem, e);
}
});
}
function reloadItem(page, item, apiClient, focusContext) {
currentItem = item, apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function(providers) {
for (var btnBrowseAllImages = page.querySelectorAll(".btnBrowseAllImages"), i = 0, length = btnBrowseAllImages.length; i < length; i++) providers.length ? btnBrowseAllImages[i].classList.remove("hide") : btnBrowseAllImages[i].classList.add("hide");
apiClient.getItemImageInfos(currentItem.Id).then(function(imageInfos) {
renderStandardImages(page, apiClient, item, imageInfos, providers), renderBackdrops(page, apiClient, item, imageInfos, providers), renderScreenshots(page, apiClient, item, imageInfos, providers), loading.hide(), layoutManager.tv && focusManager.autoFocus(focusContext || page)
})
})
currentItem = item;
apiClient.getRemoteImageProviders(getBaseRemoteOptions()).then(function (providers) {
var btnBrowseAllImages = page.querySelectorAll('.btnBrowseAllImages');
for (var i = 0, length = btnBrowseAllImages.length; i < length; i++) {
if (providers.length) {
btnBrowseAllImages[i].classList.remove('hide');
} else {
btnBrowseAllImages[i].classList.add('hide');
}
}
apiClient.getItemImageInfos(currentItem.Id).then(function (imageInfos) {
renderStandardImages(page, apiClient, item, imageInfos, providers);
renderBackdrops(page, apiClient, item, imageInfos, providers);
renderScreenshots(page, apiClient, item, imageInfos, providers);
loading.hide();
if (layoutManager.tv) {
focusManager.autoFocus((focusContext || page));
}
});
});
}
function getImageUrl(item, apiClient, type, index, options) {
return options = options || {}, options.type = type, options.index = index, options.tag = "Backdrop" === type ? item.BackdropImageTags[index] : "Screenshot" === type ? item.ScreenshotImageTags[index] : "Primary" === type ? item.PrimaryImageTag || item.ImageTags[type] : item.ImageTags[type], apiClient.getScaledImageUrl(item.Id || item.ItemId, options)
options = options || {};
options.type = type;
options.index = index;
if (type === 'Backdrop') {
options.tag = item.BackdropImageTags[index];
} else if (type === 'Screenshot') {
options.tag = item.ScreenshotImageTags[index];
} else if (type === 'Primary') {
options.tag = item.PrimaryImageTag || item.ImageTags[type];
} else {
options.tag = item.ImageTags[type];
}
// For search hints
return apiClient.getScaledImageUrl(item.Id || item.ItemId, options);
}
function getCardHtml(image, index, numImages, apiClient, imageProviders, imageSize, tagName, enableFooterButtons) {
var html = "",
cssClass = "card scalableCard imageEditorCard",
cardBoxCssClass = "cardBox visualCardBox";
return cssClass += " backdropCard backdropCard-scalable", "button" === tagName ? (cssClass += " btnImageCard", layoutManager.tv && !browser.slow && (cardBoxCssClass += " cardBox-focustransform"), layoutManager.tv && (cardBoxCssClass += " card-focuscontent cardBox-withfocuscontent"), html += '<button type="button" class="' + cssClass + '"') : html += '<div class="' + cssClass + '"', html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + index + '" data-numimages="' + numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + imageProviders.length + '"', html += ">", html += '<div class="' + cardBoxCssClass + '">', html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">', html += '<div class="cardPadder-backdrop"></div>', html += '<div class="cardContent">', html += '<div class="cardImageContainer" style="background-image:url(\'' + getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, {
maxWidth: imageSize
}) + "');background-position:center bottom;\"></div>", html += "</div>", html += "</div>", html += '<div class="cardFooter visualCardBox-cardFooter">', html += '<h3 class="cardText cardTextCentered" style="margin:0;">' + globalize.translate("sharedcomponents#" + image.ImageType) + "</h3>", html += '<div class="cardText cardText-secondary cardTextCentered">', image.Width && image.Height ? html += image.Width + " X " + image.Height : html += "&nbsp;", html += "</div>", enableFooterButtons && (html += '<div class="cardText cardTextCentered">', "Backdrop" === image.ImageType || "Screenshot" === image.ImageType ? (html += index > 0 ? '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate("sharedcomponents#MoveLeft") + '"><i class="md-icon">chevron_left</i></button>' : '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate("sharedcomponents#MoveLeft") + '"><i class="md-icon">chevron_left</i></button>', html += index < numImages - 1 ? '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex + 1) + '" title="' + globalize.translate("sharedcomponents#MoveRight") + '"><i class="md-icon">chevron_right</i></button>' : '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate("sharedcomponents#MoveRight") + '"><i class="md-icon">chevron_right</i></button>') : imageProviders.length && (html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" class="btnSearchImages autoSize" title="' + globalize.translate("sharedcomponents#Search") + '"><i class="md-icon">search</i></button>'), html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" data-index="' + (null != image.ImageIndex ? image.ImageIndex : "null") + '" class="btnDeleteImage autoSize" title="' + globalize.translate("sharedcomponents#Delete") + '"><i class="md-icon">delete</i></button>', html += "</div>"), html += "</div>", html += "</div>", html += "</" + tagName + ">"
var html = '';
var cssClass = "card scalableCard imageEditorCard";
var cardBoxCssClass = 'cardBox visualCardBox';
cssClass += " backdropCard backdropCard-scalable";
if (tagName === 'button') {
cssClass += ' btnImageCard';
if (layoutManager.tv && !browser.slow) {
cardBoxCssClass += ' cardBox-focustransform';
}
if (layoutManager.tv) {
cardBoxCssClass += ' card-focuscontent cardBox-withfocuscontent';
}
html += '<button type="button" class="' + cssClass + '"';
} else {
html += '<div class="' + cssClass + '"';
}
html += ' data-id="' + currentItem.Id + '" data-serverid="' + apiClient.serverId() + '" data-index="' + index + '" data-numimages="' + numImages + '" data-imagetype="' + image.ImageType + '" data-providers="' + imageProviders.length + '"';
html += '>';
html += '<div class="' + cardBoxCssClass + '">';
html += '<div class="cardScalable visualCardBox-cardScalable" style="background-color:transparent;">';
html += '<div class="cardPadder-backdrop"></div>';
html += '<div class="cardContent">';
var imageUrl = getImageUrl(currentItem, apiClient, image.ImageType, image.ImageIndex, { maxWidth: imageSize });
html += '<div class="cardImageContainer" style="background-image:url(\'' + imageUrl + '\');background-position:center bottom;"></div>';
html += '</div>';
html += '</div>';
html += '<div class="cardFooter visualCardBox-cardFooter">';
html += '<h3 class="cardText cardTextCentered" style="margin:0;">' + globalize.translate('sharedcomponents#' + image.ImageType) + '</h3>';
html += '<div class="cardText cardText-secondary cardTextCentered">';
if (image.Width && image.Height) {
html += image.Width + ' X ' + image.Height;
} else {
html += '&nbsp;';
}
html += '</div>';
if (enableFooterButtons) {
html += '<div class="cardText cardTextCentered">';
if (image.ImageType === "Backdrop" || image.ImageType === "Screenshot") {
if (index > 0) {
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex - 1) + '" title="' + globalize.translate('sharedcomponents#MoveLeft') + '"><i class="md-icon">chevron_left</i></button>';
} else {
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('sharedcomponents#MoveLeft') + '"><i class="md-icon">chevron_left</i></button>';
}
if (index < numImages - 1) {
html += '<button type="button" is="paper-icon-button-light" class="btnMoveImage autoSize" data-imagetype="' + image.ImageType + '" data-index="' + image.ImageIndex + '" data-newindex="' + (image.ImageIndex + 1) + '" title="' + globalize.translate('sharedcomponents#MoveRight') + '"><i class="md-icon">chevron_right</i></button>';
} else {
html += '<button type="button" is="paper-icon-button-light" class="autoSize" disabled title="' + globalize.translate('sharedcomponents#MoveRight') + '"><i class="md-icon">chevron_right</i></button>';
}
}
else {
if (imageProviders.length) {
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" class="btnSearchImages autoSize" title="' + globalize.translate('sharedcomponents#Search') + '"><i class="md-icon">search</i></button>';
}
}
html += '<button type="button" is="paper-icon-button-light" data-imagetype="' + image.ImageType + '" data-index="' + (image.ImageIndex != null ? image.ImageIndex : "null") + '" class="btnDeleteImage autoSize" title="' + globalize.translate('sharedcomponents#Delete') + '"><i class="md-icon">delete</i></button>';
html += '</div>';
}
html += '</div>';
html += '</div>';
html += '</' + tagName + '>';
return html;
}
function deleteImage(context, itemId, type, index, apiClient, enableConfirmation) {
var afterConfirm = function() {
apiClient.deleteItemImage(itemId, type, index).then(function() {
hasChanges = !0, reload(context)
})
var afterConfirm = function () {
apiClient.deleteItemImage(itemId, type, index).then(function () {
hasChanges = true;
reload(context);
});
};
if (!enableConfirmation) return void afterConfirm();
require(["confirm"], function(confirm) {
if (!enableConfirmation) {
afterConfirm();
return;
}
require(['confirm'], function (confirm) {
confirm({
text: globalize.translate("sharedcomponents#ConfirmDeleteImage"),
confirmText: globalize.translate("sharedcomponents#Delete"),
primary: "cancel"
}).then(afterConfirm)
})
text: globalize.translate('sharedcomponents#ConfirmDeleteImage'),
confirmText: globalize.translate('sharedcomponents#Delete'),
primary: 'cancel'
}).then(afterConfirm);
});
}
function moveImage(context, apiClient, itemId, type, index, newIndex, focusContext) {
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function() {
hasChanges = !0, reload(context, null, focusContext)
}, function() {
require(["alert"], function(alert) {
alert(globalize.translate("sharedcomponents#DefaultErrorMessage"))
})
})
apiClient.updateItemImageIndex(itemId, type, index, newIndex).then(function () {
hasChanges = true;
reload(context, null, focusContext);
}, function () {
require(['alert'], function (alert) {
alert(globalize.translate('sharedcomponents#DefaultErrorMessage'));
});
});
}
function renderImages(page, item, apiClient, images, imageProviders, elem) {
var html = "",
imageSize = 300,
windowSize = dom.getWindowSize();
windowSize.innerWidth >= 1280 && (imageSize = Math.round(windowSize.innerWidth / 4));
for (var tagName = layoutManager.tv ? "button" : "div", enableFooterButtons = !layoutManager.tv, i = 0, length = images.length; i < length; i++) {
html += getCardHtml(images[i], i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons)
var html = '';
var imageSize = 300;
var windowSize = dom.getWindowSize();
if (windowSize.innerWidth >= 1280) {
imageSize = Math.round(windowSize.innerWidth / 4);
}
elem.innerHTML = html, imageLoader.lazyChildren(elem)
var tagName = layoutManager.tv ? 'button' : 'div';
var enableFooterButtons = !layoutManager.tv;
for (var i = 0, length = images.length; i < length; i++) {
var image = images[i];
html += getCardHtml(image, i, length, apiClient, imageProviders, imageSize, tagName, enableFooterButtons);
}
elem.innerHTML = html;
imageLoader.lazyChildren(elem);
}
function renderStandardImages(page, apiClient, item, imageInfos, imageProviders) {
renderImages(page, item, apiClient, imageInfos.filter(function(i) {
return "Screenshot" !== i.ImageType && "Backdrop" !== i.ImageType && "Chapter" !== i.ImageType
}), imageProviders, page.querySelector("#images"))
var images = imageInfos.filter(function (i) {
return i.ImageType !== "Screenshot" && i.ImageType !== "Backdrop" && i.ImageType !== "Chapter";
});
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#images'));
}
function renderBackdrops(page, apiClient, item, imageInfos, imageProviders) {
var images = imageInfos.filter(function(i) {
return "Backdrop" === i.ImageType
}).sort(function(a, b) {
return a.ImageIndex - b.ImageIndex
var images = imageInfos.filter(function (i) {
return i.ImageType === "Backdrop";
}).sort(function (a, b) {
return a.ImageIndex - b.ImageIndex;
});
images.length ? (page.querySelector("#backdropsContainer", page).classList.remove("hide"), renderImages(page, item, apiClient, images, imageProviders, page.querySelector("#backdrops"))) : page.querySelector("#backdropsContainer", page).classList.add("hide")
if (images.length) {
page.querySelector('#backdropsContainer', page).classList.remove('hide');
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#backdrops'));
} else {
page.querySelector('#backdropsContainer', page).classList.add('hide');
}
}
function renderScreenshots(page, apiClient, item, imageInfos, imageProviders) {
var images = imageInfos.filter(function(i) {
return "Screenshot" === i.ImageType
}).sort(function(a, b) {
return a.ImageIndex - b.ImageIndex
var images = imageInfos.filter(function (i) {
return i.ImageType === "Screenshot";
}).sort(function (a, b) {
return a.ImageIndex - b.ImageIndex;
});
images.length ? (page.querySelector("#screenshotsContainer", page).classList.remove("hide"), renderImages(page, item, apiClient, images, imageProviders, page.querySelector("#screenshots"))) : page.querySelector("#screenshotsContainer", page).classList.add("hide")
if (images.length) {
page.querySelector('#screenshotsContainer', page).classList.remove('hide');
renderImages(page, item, apiClient, images, imageProviders, page.querySelector('#screenshots'));
} else {
page.querySelector('#screenshotsContainer', page).classList.add('hide');
}
}
function showImageDownloader(page, imageType) {
require(["imageDownloader"], function(ImageDownloader) {
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function() {
hasChanges = !0, reload(page)
})
})
require(['imageDownloader'], function (ImageDownloader) {
ImageDownloader.show(currentItem.Id, currentItem.ServerId, currentItem.Type, imageType).then(function () {
hasChanges = true;
reload(page);
});
});
}
function showActionSheet(context, imageCard) {
var itemId = imageCard.getAttribute("data-id"),
serverId = imageCard.getAttribute("data-serverid"),
apiClient = connectionManager.getApiClient(serverId),
type = imageCard.getAttribute("data-imagetype"),
index = parseInt(imageCard.getAttribute("data-index")),
providerCount = parseInt(imageCard.getAttribute("data-providers")),
numImages = parseInt(imageCard.getAttribute("data-numimages"));
require(["actionsheet"], function(actionSheet) {
var itemId = imageCard.getAttribute('data-id');
var serverId = imageCard.getAttribute('data-serverid');
var apiClient = connectionManager.getApiClient(serverId);
var type = imageCard.getAttribute('data-imagetype');
var index = parseInt(imageCard.getAttribute('data-index'));
var providerCount = parseInt(imageCard.getAttribute('data-providers'));
var numImages = parseInt(imageCard.getAttribute('data-numimages'));
require(['actionsheet'], function (actionSheet) {
var commands = [];
commands.push({
name: globalize.translate("sharedcomponents#Delete"),
id: "delete"
}), "Backdrop" !== type && "Screenshot" !== type || (index > 0 && commands.push({
name: globalize.translate("sharedcomponents#MoveLeft"),
id: "moveleft"
}), index < numImages - 1 && commands.push({
name: globalize.translate("sharedcomponents#MoveRight"),
id: "moveright"
})), providerCount && commands.push({
name: globalize.translate("sharedcomponents#Search"),
id: "search"
}), actionSheet.show({
name: globalize.translate('sharedcomponents#Delete'),
id: 'delete'
});
if (type === 'Backdrop' || type === 'Screenshot') {
if (index > 0) {
commands.push({
name: globalize.translate('sharedcomponents#MoveLeft'),
id: 'moveleft'
});
}
if (index < numImages - 1) {
commands.push({
name: globalize.translate('sharedcomponents#MoveRight'),
id: 'moveright'
});
}
}
if (providerCount) {
commands.push({
name: globalize.translate('sharedcomponents#Search'),
id: 'search'
});
}
actionSheet.show({
items: commands,
positionTo: imageCard
}).then(function(id) {
}).then(function (id) {
switch (id) {
case "delete":
deleteImage(context, itemId, type, index, apiClient, !1);
case 'delete':
deleteImage(context, itemId, type, index, apiClient, false);
break;
case "search":
case 'search':
showImageDownloader(context, type);
break;
case "moveleft":
moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, "itemsContainer"));
case 'moveleft':
moveImage(context, apiClient, itemId, type, index, index - 1, dom.parentWithClass(imageCard, 'itemsContainer'));
break;
case 'moveright':
moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, 'itemsContainer'));
break;
default:
break;
case "moveright":
moveImage(context, apiClient, itemId, type, index, index + 1, dom.parentWithClass(imageCard, "itemsContainer"))
}
})
})
});
});
}
function initEditor(context, options) {
for (var uploadButtons = context.querySelectorAll(".btnOpenUploadMenu"), isFileInputSupported = appHost.supports("fileinput"), i = 0, length = uploadButtons.length; i < length; i++) isFileInputSupported ? uploadButtons[i].classList.remove("hide") : uploadButtons[i].classList.add("hide");
addListeners(context, "btnOpenUploadMenu", "click", function() {
var imageType = this.getAttribute("data-imagetype");
require(["imageUploader"], function(imageUploader) {
var uploadButtons = context.querySelectorAll('.btnOpenUploadMenu');
var isFileInputSupported = appHost.supports('fileinput');
for (var i = 0, length = uploadButtons.length; i < length; i++) {
if (isFileInputSupported) {
uploadButtons[i].classList.remove('hide');
} else {
uploadButtons[i].classList.add('hide');
}
}
addListeners(context, 'btnOpenUploadMenu', 'click', function () {
var imageType = this.getAttribute('data-imagetype');
require(['imageUploader'], function (imageUploader) {
imageUploader.show({
theme: options.theme,
imageType: imageType,
itemId: currentItem.Id,
serverId: currentItem.ServerId
}).then(function(hasChanged) {
hasChanged && (hasChanges = !0, reload(context))
})
})
}), addListeners(context, "btnSearchImages", "click", function() {
showImageDownloader(context, this.getAttribute("data-imagetype"))
}), addListeners(context, "btnBrowseAllImages", "click", function() {
showImageDownloader(context, this.getAttribute("data-imagetype") || "Primary")
}), addListeners(context, "btnImageCard", "click", function() {
showActionSheet(context, this)
}), addListeners(context, "btnDeleteImage", "click", function() {
var type = this.getAttribute("data-imagetype"),
index = this.getAttribute("data-index");
index = "null" === index ? null : parseInt(index);
}).then(function (hasChanged) {
if (hasChanged) {
hasChanges = true;
reload(context);
}
});
});
});
addListeners(context, 'btnSearchImages', 'click', function () {
showImageDownloader(context, this.getAttribute('data-imagetype'));
});
addListeners(context, 'btnBrowseAllImages', 'click', function () {
showImageDownloader(context, this.getAttribute('data-imagetype') || 'Primary');
});
addListeners(context, 'btnImageCard', 'click', function () {
showActionSheet(context, this);
});
addListeners(context, 'btnDeleteImage', 'click', function () {
var type = this.getAttribute('data-imagetype');
var index = this.getAttribute('data-index');
index = index === "null" ? null : parseInt(index);
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
deleteImage(context, currentItem.Id, type, index, apiClient, !0)
}), addListeners(context, "btnMoveImage", "click", function() {
var type = this.getAttribute("data-imagetype"),
index = this.getAttribute("data-index"),
newIndex = this.getAttribute("data-newindex"),
apiClient = connectionManager.getApiClient(currentItem.ServerId);
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, "itemsContainer"))
})
deleteImage(context, currentItem.Id, type, index, apiClient, true);
});
addListeners(context, 'btnMoveImage', 'click', function () {
var type = this.getAttribute('data-imagetype');
var index = this.getAttribute('data-index');
var newIndex = this.getAttribute('data-newindex');
var apiClient = connectionManager.getApiClient(currentItem.ServerId);
moveImage(context, apiClient, currentItem.Id, type, index, newIndex, dom.parentWithClass(this, 'itemsContainer'));
});
}
function showEditor(options, resolve, reject) {
var itemId = options.itemId,
serverId = options.serverId;
loading.show(), require(["text!./imageeditor.template.html"], function(template) {
var itemId = options.itemId;
var serverId = options.serverId;
loading.show();
require(['text!./imageeditor.template.html'], function (template) {
var apiClient = connectionManager.getApiClient(serverId);
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(item) {
apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function (item) {
var dialogOptions = {
removeOnClose: !0
removeOnClose: true
};
layoutManager.tv ? dialogOptions.size = "fullscreen" : dialogOptions.size = "fullscreen-border";
if (layoutManager.tv) {
dialogOptions.size = 'fullscreen';
} else {
dialogOptions.size = 'fullscreen-border';
}
var dlg = dialogHelper.createDialog(dialogOptions);
dlg.classList.add("formDialog"), dlg.innerHTML = globalize.translateDocument(template, "sharedcomponents"), layoutManager.tv && scrollHelper.centerFocus.on(dlg, !1), initEditor(dlg, options), dlg.addEventListener("close", function() {
layoutManager.tv && scrollHelper.centerFocus.off(dlg, !1), loading.hide(), hasChanges ? resolve() : reject()
}), dialogHelper.open(dlg), reload(dlg, item), dlg.querySelector(".btnCancel").addEventListener("click", function() {
dialogHelper.close(dlg)
})
})
})
dlg.classList.add('formDialog');
dlg.innerHTML = globalize.translateDocument(template, 'sharedcomponents');
if (layoutManager.tv) {
scrollHelper.centerFocus.on(dlg, false);
}
initEditor(dlg, options);
// Has to be assigned a z-index after the call to .open()
dlg.addEventListener('close', function () {
if (layoutManager.tv) {
scrollHelper.centerFocus.off(dlg, false);
}
loading.hide();
if (hasChanges) {
resolve();
} else {
reject();
}
});
dialogHelper.open(dlg);
reload(dlg, item);
dlg.querySelector('.btnCancel').addEventListener('click', function () {
dialogHelper.close(dlg);
});
});
});
}
var currentItem, hasChanges = !1;
return {
show: function(options) {
return new Promise(function(resolve, reject) {
hasChanges = !1, showEditor(options, resolve, reject)
})
show: function (options) {
return new Promise(function (resolve, reject) {
hasChanges = false;
showEditor(options, resolve, reject);
});
}
}
};
});
@@ -1,18 +1,38 @@
define(["dom"], function(dom) {
"use strict";
define(['dom'], function (dom) {
'use strict';
function loadImage(elem, url) {
return elem ? "IMG" !== elem.tagName ? (elem.style.backgroundImage = "url('" + url + "')", Promise.resolve()) : loadImageIntoImg(elem, url) : Promise.reject("elem cannot be null")
if (!elem) {
return Promise.reject('elem cannot be null');
}
if (elem.tagName !== "IMG") {
elem.style.backgroundImage = "url('" + url + "')";
return Promise.resolve();
//return loadImageIntoImg(document.createElement('img'), url).then(function () {
// elem.style.backgroundImage = "url('" + url + "')";
// return Promise.resolve();
//});
}
return loadImageIntoImg(elem, url);
}
function loadImageIntoImg(elem, url) {
return new Promise(function(resolve, reject) {
dom.addEventListener(elem, "load", resolve, {
once: !0
}), elem.setAttribute("src", url)
})
return new Promise(function (resolve, reject) {
dom.addEventListener(elem, 'load', resolve, {
once: true
});
elem.setAttribute("src", url);
});
}
return {
loadImage: loadImage
}
};
});
+216 -43
View File
@@ -1,82 +1,255 @@
define(["lazyLoader", "imageFetcher", "layoutManager", "browser", "appSettings", "require", "css!./style"], function(lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) {
"use strict";
define(['lazyLoader', 'imageFetcher', 'layoutManager', 'browser', 'appSettings', 'require', 'css!./style'], function (lazyLoader, imageFetcher, layoutManager, browser, appSettings, require) {
'use strict';
var requestIdleCallback = window.requestIdleCallback || function (fn) {
fn();
};
var self = {};
// seeing slow performance with firefox
var enableFade = false;
function fillImage(elem, source, enableEffects) {
if (!elem) throw new Error("elem cannot be null");
source || (source = elem.getAttribute("data-src")), source && fillImageElement(elem, source, enableEffects)
if (!elem) {
throw new Error('elem cannot be null');
}
if (!source) {
source = elem.getAttribute('data-src');
}
if (!source) {
return;
}
fillImageElement(elem, source, enableEffects);
}
function fillImageElement(elem, source, enableEffects) {
imageFetcher.loadImage(elem, source).then(function() {
enableFade && !1 !== enableEffects && fadeIn(elem), elem.removeAttribute("data-src")
})
imageFetcher.loadImage(elem, source).then(function () {
var fillingVibrant = false;//fillVibrant(elem, source);
if (enableFade && enableEffects !== false && !fillingVibrant) {
fadeIn(elem);
}
elem.removeAttribute("data-src");
});
}
function fillVibrant(img, url, canvas, canvasContext) {
var vibrantElement = img.getAttribute('data-vibrant');
if (!vibrantElement) {
return false;
}
if (window.Vibrant) {
fillVibrantOnLoaded(img, url, vibrantElement, canvas, canvasContext);
return true;
}
require(['vibrant'], function () {
fillVibrantOnLoaded(img, url, vibrantElement, canvas, canvasContext);
});
return true;
}
function fillVibrantOnLoaded(img, url, vibrantElement) {
vibrantElement = document.getElementById(vibrantElement);
if (!vibrantElement) {
return;
}
requestIdleCallback(function () {
//var now = new Date().getTime();
getVibrantInfoFromElement(img, url).then(function (vibrantInfo) {
var swatch = vibrantInfo.split('|');
//console.log('vibrant took ' + (new Date().getTime() - now) + 'ms');
if (swatch.length) {
var index = 0;
var style = vibrantElement.style;
style.backgroundColor = swatch[index];
style.color = swatch[index + 1];
var classList = vibrantElement.classList;
if (classList.contains('cardFooter')) {
classList.add('cardFooter-vibrant');
} else {
classList.add('vibrant');
}
}
});
});
/*
* Results into:
* Vibrant #7a4426
* Muted #7b9eae
* DarkVibrant #348945
* DarkMuted #141414
* LightVibrant #f3ccb4
*/
}
function getVibrantInfoFromElement(elem, url) {
return new Promise(function(resolve, reject) {
require(["vibrant"], function() {
if ("IMG" === elem.tagName) return void resolve(getVibrantInfo(elem, url));
var img = new Image;
img.onload = function() {
resolve(getVibrantInfo(img, url))
}, img.src = url
})
})
return new Promise(function (resolve, reject) {
require(['vibrant'], function () {
if (elem.tagName === 'IMG') {
resolve(getVibrantInfo(elem, url));
return;
}
var img = new Image();
img.onload = function () {
resolve(getVibrantInfo(img, url));
};
img.src = url;
});
});
}
function getSettingsKey(url) {
var parts = url.split("://");
url = parts[parts.length - 1], url = url.substring(url.indexOf("/") + 1), url = url.split("?")[0];
return "vibrant31" + url
var parts = url.split('://');
url = parts[parts.length - 1];
url = url.substring(url.indexOf('/') + 1);
url = url.split('?')[0];
var cacheKey = 'vibrant31';
//cacheKey = 'vibrant' + new Date().getTime();
return cacheKey + url;
}
function getCachedVibrantInfo(url) {
return appSettings.get(getSettingsKey(url))
return appSettings.get(getSettingsKey(url));
}
function getVibrantInfo(img, url) {
var value = getCachedVibrantInfo(url);
if (value) return value;
var vibrant = new Vibrant(img),
swatches = vibrant.swatches();
return value = "", value += getSwatchString(swatches.DarkVibrant), appSettings.set(getSettingsKey(url), value), value
if (value) {
return value;
}
var vibrant = new Vibrant(img);
var swatches = vibrant.swatches();
value = '';
var swatch = swatches.DarkVibrant;
value += getSwatchString(swatch);
appSettings.set(getSettingsKey(url), value);
return value;
}
function getSwatchString(swatch) {
return swatch ? swatch.getHex() + "|" + swatch.getBodyTextColor() + "|" + swatch.getTitleTextColor() : "||"
if (swatch) {
return swatch.getHex() + '|' + swatch.getBodyTextColor() + '|' + swatch.getTitleTextColor();
}
return '||';
}
function fadeIn(elem) {
elem.classList.add("lazy-image-fadein")
var cssClass = 'lazy-image-fadein';
elem.classList.add(cssClass);
}
function lazyChildren(elem) {
lazyLoader.lazyChildren(elem, fillImage)
lazyLoader.lazyChildren(elem, fillImage);
}
function getPrimaryImageAspectRatio(items) {
for (var values = [], i = 0, length = items.length; i < length; i++) {
var values = [];
for (var i = 0, length = items.length; i < length; i++) {
var ratio = items[i].PrimaryImageAspectRatio || 0;
ratio && (values[values.length] = ratio)
if (!ratio) {
continue;
}
values[values.length] = ratio;
}
if (!values.length) return null;
values.sort(function(a, b) {
return a - b
});
var result, half = Math.floor(values.length / 2);
result = values.length % 2 ? values[half] : (values[half - 1] + values[half]) / 2;
if (Math.abs(2 / 3 - result) <= .15) return 2 / 3;
if (Math.abs(16 / 9 - result) <= .2) return 16 / 9;
if (Math.abs(1 - result) <= .15) return 1;
return Math.abs(4 / 3 - result) <= .15 ? 4 / 3 : result
if (!values.length) {
return null;
}
// Use the median
values.sort(function (a, b) { return a - b; });
var half = Math.floor(values.length / 2);
var result;
if (values.length % 2) {
result = values[half];
}
else {
result = (values[half - 1] + values[half]) / 2.0;
}
// If really close to 2:3 (poster image), just return 2:3
var aspect2x3 = 2 / 3;
if (Math.abs(aspect2x3 - result) <= 0.15) {
return aspect2x3;
}
// If really close to 16:9 (episode image), just return 16:9
var aspect16x9 = 16 / 9;
if (Math.abs(aspect16x9 - result) <= 0.2) {
return aspect16x9;
}
// If really close to 1 (square image), just return 1
if (Math.abs(1 - result) <= 0.15) {
return 1;
}
// If really close to 4:3 (poster image), just return 2:3
var aspect4x3 = 4 / 3;
if (Math.abs(aspect4x3 - result) <= 0.15) {
return aspect4x3;
}
return result;
}
function fillImages(elems) {
for (var i = 0, length = elems.length; i < length; i++) {
fillImage(elems[0])
var elem = elems[0];
fillImage(elem);
}
}
var self = (window.requestIdleCallback, {}),
enableFade = !1;
return self.fillImages = fillImages, self.lazyImage = fillImage, self.lazyChildren = lazyChildren, self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio, self.getCachedVibrantInfo = getCachedVibrantInfo, self.getVibrantInfoFromElement = getVibrantInfoFromElement, self
self.fillImages = fillImages;
self.lazyImage = fillImage;
self.lazyChildren = lazyChildren;
self.getPrimaryImageAspectRatio = getPrimaryImageAspectRatio;
self.getCachedVibrantInfo = getCachedVibrantInfo;
self.getVibrantInfoFromElement = getVibrantInfoFromElement;
return self;
});

Some files were not shown because too many files have changed in this diff Show More