mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
merge branch master into books
This commit is contained in:
commit
09e051bfab
78 changed files with 714 additions and 664 deletions
|
@ -197,7 +197,9 @@ export function show(options) {
|
|||
menuItemClass += ' actionsheet-xlargeFont';
|
||||
}
|
||||
|
||||
for (let [i, item] of options.items.entries()) {
|
||||
// 'options.items' is HTMLOptionsCollection, so no fancy loops
|
||||
for (let i = 0; i < options.items.length; i++) {
|
||||
const item = options.items[i];
|
||||
|
||||
if (item.divider) {
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinManager', 'pluginManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, layoutManager, skinManager, pluginManager, backdrop, browser, page, appSettings, appHost, connectionManager) {
|
||||
define(['loading', 'globalize', 'events', 'viewManager', 'skinManager', 'backdrop', 'browser', 'page', 'appSettings', 'apphost', 'connectionManager'], function (loading, globalize, events, viewManager, skinManager, backdrop, browser, page, appSettings, appHost, connectionManager) {
|
||||
'use strict';
|
||||
|
||||
var appRouter = {
|
||||
|
|
|
@ -306,6 +306,10 @@ button::-moz-focus-inner {
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
.dialog .cardText {
|
||||
text-overflow: initial;
|
||||
}
|
||||
|
||||
.cardText-secondary {
|
||||
font-size: 86%;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'act
|
|||
|
||||
function getEditorHtml() {
|
||||
var html = '';
|
||||
html += '<div class="formDialogContent">';
|
||||
html += '<div class="formDialogContent smoothScrollY">';
|
||||
html += '<div class="dialogContentInner dialog-content-centered">';
|
||||
html += '<form style="margin:auto;">';
|
||||
html += '<h1>' + globalize.translate('HeaderChannels') + '</h1>';
|
||||
|
|
|
@ -126,25 +126,10 @@
|
|||
}
|
||||
|
||||
@media all and (min-width: 80em) and (min-height: 45em) {
|
||||
.dialog-medium {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
.dialog-medium-tall {
|
||||
width: 80%;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.dialog-small {
|
||||
width: 60%;
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
.dialog-fullscreen-border {
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.noScroll {
|
||||
|
|
|
@ -253,7 +253,7 @@ define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-in
|
|||
var systemInfo = responses[0];
|
||||
var initialPath = responses[1];
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'medium-tall',
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.formDialogHeaderTitle:first-child {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.formDialogContent:not(.no-grow) {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
@ -46,10 +50,16 @@
|
|||
right: 0;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
padding: 1.25em 1em;
|
||||
padding: 1em 1em;
|
||||
|
||||
/* Without this emby-checkbox is able to appear on top */
|
||||
z-index: 1;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.layout-tv .formDialogFooter {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
@ -69,8 +79,12 @@
|
|||
|
||||
.formDialogFooterItem {
|
||||
margin: 0.5em !important;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
flex-basis: 12em;
|
||||
}
|
||||
|
||||
.layout-tv .formDialogFooterItem {
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa
|
|||
function hidePrePlaybackPage() {
|
||||
let animatedPage = document.querySelector('.page:not(.hide)');
|
||||
animatedPage.classList.add('hide');
|
||||
// At this point, we must hide the scrollbar placeholder, so it's not being displayed while the item is being loaded
|
||||
document.body.classList.remove('force-scroll');
|
||||
}
|
||||
|
||||
function zoomIn(elem) {
|
||||
|
|
|
@ -334,7 +334,7 @@ define(['dom', 'loading', 'apphost', 'dialogHelper', 'connectionManager', 'image
|
|||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'fullscreen-border';
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="formDialogContent">
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
<div class="dialogContentInner">
|
||||
<div class="flex align-items-center justify-content-center flex-wrap-wrap" style="margin: 2em 0;">
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ define(['globalize', 'dom', 'dialogHelper', 'emby-checkbox', 'emby-select', 'emb
|
|||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'medium-tall',
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
});
|
||||
|
|
|
@ -137,7 +137,7 @@ define(['dialogHelper', 'connectionManager', 'dom', 'loading', 'scrollHelper', '
|
|||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'fullscreen-border';
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="formDialogContent">
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
<div class="dialogContentInner">
|
||||
|
||||
<form class="uploadItemImageForm" style="max-width: 100%;">
|
||||
|
|
|
@ -457,7 +457,7 @@ define(['dialogHelper', 'connectionManager', 'loading', 'dom', 'layoutManager',
|
|||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'fullscreen-border';
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="formDialogContent">
|
||||
<div class="formDialogContent smoothScrollY">
|
||||
<div class="dialogContentInner">
|
||||
|
||||
<div id="imagesContainer">
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
define(['dom'], function (dom) {
|
||||
'use strict';
|
||||
|
||||
function loadImage(elem, url) {
|
||||
|
||||
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: true
|
||||
});
|
||||
elem.setAttribute('src', url);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
loadImage: loadImage
|
||||
};
|
||||
|
||||
});
|
|
@ -450,7 +450,7 @@ define(['apphost', 'globalize', 'connectionManager', 'itemHelper', 'appRouter',
|
|||
navigator.share({
|
||||
title: item.Name,
|
||||
text: item.Overview,
|
||||
url: 'https://github.com/jellyfin/jellyfin'
|
||||
url: `${apiClient.serverAddress()}/web/index.html#!/${appRouter.getRouteUrl(item)}`
|
||||
});
|
||||
break;
|
||||
case 'album':
|
||||
|
|
|
@ -348,7 +348,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
|||
currentItemType = currentItem.Type;
|
||||
|
||||
var dialogOptions = {
|
||||
size: 'fullscreen-border',
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
@ -429,7 +429,7 @@ define(['dialogHelper', 'loading', 'connectionManager', 'require', 'globalize',
|
|||
require(['text!./itemidentifier.template.html'], function (template) {
|
||||
|
||||
var dialogOptions = {
|
||||
size: 'fullscreen-border',
|
||||
size: 'small',
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
};
|
||||
|
|
|
@ -187,7 +187,7 @@ define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionsed
|
|||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'medium-tall',
|
||||
size: 'small',
|
||||
modal: false,
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
|
|
|
@ -204,7 +204,7 @@ define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionsed
|
|||
xhr.onload = function (e) {
|
||||
var template = this.response;
|
||||
var dlg = dialogHelper.createDialog({
|
||||
size: 'medium-tall',
|
||||
size: 'small',
|
||||
modal: false,
|
||||
removeOnClose: true,
|
||||
scrollY: false
|
||||
|
|
|
@ -245,50 +245,6 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
|||
});
|
||||
}
|
||||
|
||||
function showMoreMenu(context, button, user) {
|
||||
|
||||
require(['itemContextMenu'], function (itemContextMenu) {
|
||||
|
||||
var item = currentItem;
|
||||
|
||||
itemContextMenu.show({
|
||||
|
||||
item: item,
|
||||
positionTo: button,
|
||||
edit: false,
|
||||
editImages: true,
|
||||
editSubtitles: true,
|
||||
sync: false,
|
||||
share: false,
|
||||
play: false,
|
||||
queue: false,
|
||||
user: user
|
||||
|
||||
}).then(function (result) {
|
||||
|
||||
if (result.deleted) {
|
||||
afterDeleted(context, item);
|
||||
|
||||
} else if (result.updated) {
|
||||
reload(context, item.Id, item.ServerId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function afterDeleted(context, item) {
|
||||
|
||||
var parentId = item.ParentId || item.SeasonId || item.SeriesId;
|
||||
|
||||
if (parentId) {
|
||||
reload(context, parentId, item.ServerId);
|
||||
} else {
|
||||
require(['appRouter'], function (appRouter) {
|
||||
appRouter.goHome();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function onEditorClick(e) {
|
||||
|
||||
var btnRemoveFromEditorList = dom.parentWithClass(e.target, 'btnRemoveFromEditorList');
|
||||
|
@ -307,6 +263,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
|||
return connectionManager.getApiClient(currentItem.ServerId);
|
||||
}
|
||||
|
||||
function bindAll(elems, eventName, fn) {
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener(eventName, fn);
|
||||
}
|
||||
}
|
||||
|
||||
function init(context, apiClient) {
|
||||
|
||||
context.querySelector('.externalIds').addEventListener('click', function (e) {
|
||||
|
@ -322,19 +284,16 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
|||
}
|
||||
});
|
||||
|
||||
context.querySelector('.btnCancel').addEventListener('click', function () {
|
||||
if (!layoutManager.desktop) {
|
||||
context.querySelector('.btnBack').classList.remove('hide');
|
||||
context.querySelector('.btnClose').classList.add('hide');
|
||||
}
|
||||
|
||||
bindAll(context.querySelectorAll('.btnCancel'), 'click', function (event) {
|
||||
event.preventDefault();
|
||||
closeDialog(false);
|
||||
});
|
||||
|
||||
context.querySelector('.btnMore').addEventListener('click', function (e) {
|
||||
|
||||
getApiClient().getCurrentUser().then(function (user) {
|
||||
showMoreMenu(context, e.target, user);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
context.querySelector('.btnHeaderSave').addEventListener('click', function (e) {
|
||||
|
||||
context.querySelector('.btnSave').click();
|
||||
|
@ -349,8 +308,8 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
|||
}
|
||||
});
|
||||
|
||||
context.removeEventListener('click', onEditorClick);
|
||||
context.addEventListener('click', onEditorClick);
|
||||
context.removeEventListener('submit', onEditorClick);
|
||||
context.addEventListener('submit', onEditorClick);
|
||||
|
||||
var form = context.querySelector('form');
|
||||
form.removeEventListener('submit', onSubmit);
|
||||
|
@ -1077,7 +1036,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi
|
|||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'medium-tall';
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><span class="material-icons arrow_back"></span></button>
|
||||
<button is="paper-icon-button-light" class="btnCancel btnBack autoSize hide" tabindex="-1"><span class="material-icons arrow_back"></span></button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
${Edit}
|
||||
</h3>
|
||||
|
@ -8,8 +8,8 @@
|
|||
<span class="material-icons check"></span>
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnMore autoSize" tabindex="-1">
|
||||
<span class="material-icons more_vert"></span>
|
||||
<button is="paper-icon-button-light" class="btnCancel btnClose autoSize" tabindex="-1">
|
||||
<span class="material-icons close"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -57,11 +57,13 @@
|
|||
<div id="fldAlbum" class="hide inputContainer">
|
||||
<input is="emby-input" id="txtAlbum" type="text" label="${LabelAlbum}" />
|
||||
</div>
|
||||
<div id="fldParentIndexNumber" class="hide inputContainer">
|
||||
<input is="emby-input" id="txtParentIndexNumber" type="number" />
|
||||
</div>
|
||||
<div id="fldIndexNumber" class="hide inputContainer">
|
||||
<input is="emby-input" id="txtIndexNumber" type="number" pattern="[0-9]*" />
|
||||
<div class="inlineForm">
|
||||
<div id="fldParentIndexNumber" class="hide inputContainer">
|
||||
<input is="emby-input" id="txtParentIndexNumber" type="number" />
|
||||
</div>
|
||||
<div id="fldIndexNumber" class="hide inputContainer">
|
||||
<input is="emby-input" id="txtIndexNumber" type="number" pattern="[0-9]*" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="fldCommunityRating" class="hide inputContainer">
|
||||
<input is="emby-input" id="txtCommunityRating" type="number" step=".1" min="0" max="10" label="${LabelCommunityRating}" />
|
||||
|
@ -129,24 +131,28 @@
|
|||
<div id="fldSeriesRuntime" class="inputContainer hide">
|
||||
<input is="emby-input" id="txtSeriesRuntime" type="number" label="${LabelRuntimeMinutes}" />
|
||||
</div>
|
||||
<div id="fldOfficialRating" class="selectContainer hide">
|
||||
<select is="emby-select" id="selectOfficialRating" label="${LabelParentalRating}"></select>
|
||||
<div class="inlineForm">
|
||||
<div id="fldOfficialRating" class="selectContainer hide">
|
||||
<select is="emby-select" id="selectOfficialRating" label="${LabelParentalRating}"></select>
|
||||
</div>
|
||||
<div id="fldCustomRating" class="selectContainer hide">
|
||||
<select is="emby-select" id="selectCustomRating" label="${LabelCustomRating}"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="fldCustomRating" class="selectContainer hide">
|
||||
<select is="emby-select" id="selectCustomRating" label="${LabelCustomRating}"></select>
|
||||
</div>
|
||||
<div id="fldOriginalAspectRatio" class="inputContainer hide">
|
||||
<input is="emby-input" id="txtOriginalAspectRatio" type="text" label="${LabelOriginalAspectRatio}" />
|
||||
</div>
|
||||
<div id="fld3dFormat" class="selectContainer hide">
|
||||
<select is="emby-select" id="select3dFormat" label="${Label3DFormat}">
|
||||
<option value=""></option>
|
||||
<option value="HalfSideBySide">HSBS</option>
|
||||
<option value="HalfTopAndBottom">HTAB</option>
|
||||
<option value="FullSideBySide">FSBS</option>
|
||||
<option value="FullTopAndBottom">FTAB</option>
|
||||
<option value="MVC">MVC</option>
|
||||
</select>
|
||||
<div class="inlineForm">
|
||||
<div id="fldOriginalAspectRatio" class="inputContainer hide">
|
||||
<input is="emby-input" id="txtOriginalAspectRatio" type="text" label="${LabelOriginalAspectRatio}" />
|
||||
</div>
|
||||
<div id="fld3dFormat" class="selectContainer hide">
|
||||
<select is="emby-select" id="select3dFormat" label="${Label3DFormat}">
|
||||
<option value=""></option>
|
||||
<option value="HalfSideBySide">HSBS</option>
|
||||
<option value="HalfTopAndBottom">HTAB</option>
|
||||
<option value="FullSideBySide">FSBS</option>
|
||||
<option value="FullTopAndBottom">FTAB</option>
|
||||
<option value="MVC">MVC</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="fldDisplayOrder" class="fldDisplaySetting selectContainer hide">
|
||||
|
@ -160,14 +166,16 @@
|
|||
<h2>
|
||||
${HeaderSpecialEpisodeInfo}
|
||||
</h2>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtAirsBeforeSeason" type="number" pattern="[0-9]*" label="${LabelAirsBeforeSeason}" />
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtAirsAfterSeason" type="number" pattern="[0-9]*" label="${LabelAirsAfterSeason}" />
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtAirsBeforeEpisode" type="number" pattern="[0-9]*" label="${LabelAirsBeforeEpisode}" />
|
||||
<div class="inlineForm">
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtAirsBeforeSeason" type="number" pattern="[0-9]*" label="${LabelAirsBeforeSeason}" />
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtAirsAfterSeason" type="number" pattern="[0-9]*" label="${LabelAirsAfterSeason}" />
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtAirsBeforeEpisode" type="number" pattern="[0-9]*" label="${LabelAirsBeforeEpisode}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -240,8 +248,11 @@
|
|||
</div>
|
||||
<br />
|
||||
<div class="formDialogFooter">
|
||||
<button is="emby-button" class="raised button-cancel block btnCancel formDialogFooterItem">
|
||||
<span>${Cancel}</span>
|
||||
</button>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block btnSave formDialogFooterItem">
|
||||
<span>${Save}</span>
|
||||
<span>${SaveChanges}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-but
|
|||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
} else {
|
||||
dialogOptions.size = 'medium-tall';
|
||||
dialogOptions.size = 'small';
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
define(['events'], function (events) {
|
||||
define(['events', 'globalize'], function (events, globalize) {
|
||||
'use strict';
|
||||
|
||||
// TODO: replace with each plugin version
|
||||
var cacheParam = new Date().getTime();
|
||||
|
||||
function loadStrings(plugin, globalize) {
|
||||
function loadStrings(plugin) {
|
||||
var strings = plugin.getTranslations ? plugin.getTranslations() : [];
|
||||
return globalize.loadStrings({
|
||||
name: plugin.id || plugin.packageName,
|
||||
|
@ -25,68 +25,78 @@ define(['events'], function (events) {
|
|||
this.pluginsList = [];
|
||||
}
|
||||
|
||||
PluginManager.prototype.loadPlugin = function (url) {
|
||||
PluginManager.prototype.loadPlugin = function(pluginSpec) {
|
||||
|
||||
console.debug('Loading plugin: ' + url);
|
||||
var instance = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
function registerPlugin(plugin) {
|
||||
instance.register(plugin);
|
||||
|
||||
require([url, 'globalize', 'appRouter'], function (pluginFactory, globalize, appRouter) {
|
||||
|
||||
var plugin = new pluginFactory();
|
||||
|
||||
// See if it's already installed
|
||||
var existing = instance.pluginsList.filter(function (p) {
|
||||
return p.id === plugin.id;
|
||||
})[0];
|
||||
|
||||
if (existing) {
|
||||
resolve(url);
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.installUrl = url;
|
||||
|
||||
var urlLower = url.toLowerCase();
|
||||
if (urlLower.indexOf('http:') === -1 && urlLower.indexOf('https:') === -1 && urlLower.indexOf('file:') === -1) {
|
||||
if (url.indexOf(appRouter.baseUrl()) !== 0) {
|
||||
|
||||
url = appRouter.baseUrl() + '/' + url;
|
||||
}
|
||||
}
|
||||
|
||||
var separatorIndex = Math.max(url.lastIndexOf('/'), url.lastIndexOf('\\'));
|
||||
plugin.baseUrl = url.substring(0, separatorIndex);
|
||||
|
||||
var paths = {};
|
||||
paths[plugin.id] = plugin.baseUrl;
|
||||
|
||||
requirejs.config({
|
||||
waitSeconds: 0,
|
||||
paths: paths
|
||||
if (plugin.getRoutes) {
|
||||
plugin.getRoutes().forEach(function (route) {
|
||||
definePluginRoute(instance, route, plugin);
|
||||
});
|
||||
}
|
||||
|
||||
instance.register(plugin);
|
||||
if (plugin.type === 'skin') {
|
||||
|
||||
if (plugin.getRoutes) {
|
||||
plugin.getRoutes().forEach(function (route) {
|
||||
definePluginRoute(instance, route, plugin);
|
||||
// translations won't be loaded for skins until needed
|
||||
return Promise.resolve(plugin);
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
loadStrings(plugin)
|
||||
.then(function () {
|
||||
resolve(plugin);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof pluginSpec === 'string') {
|
||||
console.debug('Loading plugin (via deprecated requirejs method): ' + pluginSpec);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
require([pluginSpec], (pluginFactory) => {
|
||||
var plugin = new pluginFactory();
|
||||
|
||||
// See if it's already installed
|
||||
var existing = instance.pluginsList.filter(function (p) {
|
||||
return p.id === plugin.id;
|
||||
})[0];
|
||||
|
||||
if (existing) {
|
||||
resolve(pluginSpec);
|
||||
}
|
||||
|
||||
plugin.installUrl = pluginSpec;
|
||||
|
||||
var separatorIndex = Math.max(pluginSpec.lastIndexOf('/'), pluginSpec.lastIndexOf('\\'));
|
||||
plugin.baseUrl = pluginSpec.substring(0, separatorIndex);
|
||||
|
||||
var paths = {};
|
||||
paths[plugin.id] = plugin.baseUrl;
|
||||
|
||||
requirejs.config({
|
||||
waitSeconds: 0,
|
||||
paths: paths
|
||||
});
|
||||
}
|
||||
|
||||
if (plugin.type === 'skin') {
|
||||
|
||||
// translations won't be loaded for skins until needed
|
||||
resolve(plugin);
|
||||
} else {
|
||||
|
||||
loadStrings(plugin, globalize).then(function () {
|
||||
resolve(plugin);
|
||||
}, reject);
|
||||
}
|
||||
registerPlugin(plugin).then(resolve).catch(reject);
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (pluginSpec.then) {
|
||||
return pluginSpec.then(pluginBuilder => {
|
||||
return pluginBuilder();
|
||||
}).then(plugin => {
|
||||
console.debug(`Plugin loaded: ${plugin.id}`);
|
||||
return registerPlugin(plugin);
|
||||
});
|
||||
} else {
|
||||
const err = new Error('Plugins have to be a Promise that resolves to a plugin builder function or a requirejs urls (deprecated)');
|
||||
console.error(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
};
|
||||
|
||||
// In lieu of automatic discovery, plugins will register dynamic objects
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdrop', 'globalize', 'require', 'appSettings'], function (appHost, userSettings, browser, events, pluginManager, backdrop, globalize, require, appSettings) {
|
||||
define(['apphost', 'userSettings', 'browser', 'events', 'backdrop', 'globalize', 'require', 'appSettings'], function (appHost, userSettings, browser, events, backdrop, globalize, require, appSettings) {
|
||||
'use strict';
|
||||
|
||||
var themeStyleElement;
|
||||
|
@ -137,6 +137,8 @@ define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdr
|
|||
|
||||
function onViewBeforeShow(e) {
|
||||
if (e.detail && e.detail.type === 'video-osd') {
|
||||
// This removes the space that the scrollbar takes while playing a video
|
||||
document.body.classList.remove('force-scroll');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -155,6 +157,9 @@ define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdr
|
|||
}
|
||||
}
|
||||
}
|
||||
// This keeps the scrollbar always present in all pages, so we avoid clipping while switching between pages
|
||||
// that need the scrollbar and pages that don't.
|
||||
document.body.classList.add('force-scroll');
|
||||
}
|
||||
|
||||
document.addEventListener('viewshow', onViewBeforeShow);
|
||||
|
|
|
@ -438,6 +438,9 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
|
|||
|
||||
inputManager.off(window, onInputCommand);
|
||||
document.removeEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove);
|
||||
// Shows page scrollbar
|
||||
document.body.classList.remove('hide-scroll');
|
||||
document.body.classList.add('force-scroll');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -603,6 +606,9 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f
|
|||
*/
|
||||
self.show = function () {
|
||||
createElements(options);
|
||||
// Hides page scrollbar
|
||||
document.body.classList.remove('force-scroll');
|
||||
document.body.classList.add('hide-scroll');
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue