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

update routes for plugin and session pages

This commit is contained in:
dkanada 2020-07-26 15:40:12 +09:00
parent c0261ee487
commit a085bb5269
24 changed files with 39 additions and 28 deletions

View file

@ -0,0 +1,18 @@
<div data-role="page" class="page standalonePage">
<div class="padded-left padded-right padded-bottom-page">
<form class="addServerForm" style="margin: 0 auto;" novalidate>
<h1>${HeaderConnectToServer}</h1>
<div class="inputContainer">
<input is="emby-input" type="url" id="txtServerHost" required="required" label="${LabelServerHost}"/>
<div class="fieldDescription">${LabelServerHostHelp}</div>
</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 btnCancel">
<span>${ButtonCancel}</span>
</button>
</form>
</div>
</div>

View file

@ -0,0 +1,72 @@
import appSettings from 'appSettings';
import loading from 'loading';
import browser from 'browser';
import globalize from 'globalize';
import 'emby-button';
/* eslint-disable indent */
function handleConnectionResult(page, result) {
loading.hide();
switch (result.State) {
case 'SignedIn': {
const apiClient = result.ApiClient;
Dashboard.onServerChanged(apiClient.getCurrentUserId(), apiClient.accessToken(), apiClient);
Dashboard.navigate('home.html');
break;
}
case 'ServerSignIn':
Dashboard.navigate('login.html?serverid=' + result.Servers[0].Id, false, 'none');
break;
case 'ServerSelection':
Dashboard.navigate('selectserver.html', false, 'none');
break;
case 'ServerUpdateNeeded':
Dashboard.alert({
message: globalize.translate('ServerUpdateNeeded', '<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>')
});
break;
case 'Unavailable':
Dashboard.alert({
message: globalize.translate('MessageUnableToConnectToServer'),
title: globalize.translate('HeaderConnectionFailure')
});
}
}
function submitServer(page) {
loading.show();
const host = page.querySelector('#txtServerHost').value;
ConnectionManager.connectToAddress(host, {
enableAutoLogin: appSettings.enableAutoLogin()
}).then(function(result) {
handleConnectionResult(page, result);
}, function() {
handleConnectionResult(page, {
State: 'Unavailable'
});
});
}
export default function(view, params) {
view.querySelector('.addServerForm').addEventListener('submit', onServerSubmit);
view.querySelector('.btnCancel').addEventListener('click', goBack);
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
function onServerSubmit(e) {
submitServer(view);
e.preventDefault();
return false;
}
function goBack() {
import('appRouter').then(({default: appRouter}) => {
appRouter.back();
});
}
}
/* eslint-enable indent */

View file

@ -0,0 +1,24 @@
<div data-role="page" id="forgotPasswordPage" class="page standalonePage forgotPasswordPage">
<div class="padded-left padded-right padded-bottom-page">
<form class="forgotPasswordForm" style="text-align: center; margin: 0 auto;">
<div style="text-align: left;">
<h1>${HeaderForgotPassword}</h1>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtName" label="${LabelUser}" autocomplete="off"/>
<div class="fieldDescription">${LabelForgotPasswordUsernameHelp}</div>
</div>
<div>
<button is="emby-button" type="submit" class="raised submit block">
<span>${ButtonSubmit}</span>
</button>
<button is="emby-button" type="button" class="raised cancel block btnCancel" onclick="history.back();">
<span>${ButtonCancel}</span>
</button>
</div>
</div>
</form>
</div>
</div>

View file

@ -0,0 +1,55 @@
import globalize from 'globalize';
/* eslint-disable indent */
function processForgotPasswordResult(result) {
if ('ContactAdmin' == result.Action) {
return void Dashboard.alert({
message: globalize.translate('MessageContactAdminToResetPassword'),
title: globalize.translate('HeaderForgotPassword')
});
}
if ('InNetworkRequired' == result.Action) {
return void Dashboard.alert({
message: globalize.translate('MessageForgotPasswordInNetworkRequired'),
title: globalize.translate('HeaderForgotPassword')
});
}
if ('PinCode' == result.Action) {
let msg = globalize.translate('MessageForgotPasswordFileCreated');
msg += '<br/>';
msg += '<br/>';
msg += 'Enter PIN here to finish Password Reset<br/>';
msg += '<br/>';
msg += result.PinFile;
msg += '<br/>';
return void Dashboard.alert({
message: msg,
title: globalize.translate('HeaderForgotPassword'),
callback: function () {
Dashboard.navigate('forgotpasswordpin.html');
}
});
}
}
export default function (view, params) {
function onSubmit(e) {
ApiClient.ajax({
type: 'POST',
url: ApiClient.getUrl('Users/ForgotPassword'),
dataType: 'json',
data: {
EnteredUsername: view.querySelector('#txtName').value
}
}).then(processForgotPasswordResult);
e.preventDefault();
return false;
}
view.querySelector('form').addEventListener('submit', onSubmit);
}
/* eslint-enable indent */

View file

@ -0,0 +1,57 @@
<div id="loginPage" data-role="page" class="page standalonePage flex flex-direction-column" data-backbutton="false">
<div class="padded-left padded-right padded-bottom-page margin-auto-y">
<form class="manualLoginForm margin-auto-x hide">
<div class="padded-left padded-right flex align-items-center justify-content-center">
<h1 class="sectionTitle">${HeaderPleaseSignIn}</h1>
</div>
<div style="height:0; overflow: hidden;">
<input type="text" name="fakeusernameremembered" tabindex="-1" />
<input type="password" name="fakepasswordremembered" tabindex="-1" />
</div>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtManualName" required="required" label="${LabelUser}" autocomplete="username" autocapitalize="off" />
</div>
<div class="inputContainer">
<input is="emby-input" id="txtManualPassword" type="password" label="${LabelPassword}" autocomplete="current-password" />
</div>
<label class="checkboxContainer">
<input is="emby-checkbox" type="checkbox" class="chkRememberLogin" checked />
<span>${RememberMe}</span>
</label>
<button is="emby-button" type="submit" class="raised button-submit block">
<span>${ButtonSignIn}</span>
</button>
<div style="margin-top:.5em;">
<button is="emby-button" type="button" class="raised cancel block btnCancel">
<span>${ButtonCancel}</span>
</button>
</div>
</form>
<div class="visualLoginForm" style="text-align: center;">
<h1 style="margin-top:1em;">${HeaderPleaseSignIn}</h1>
<div id="divUsers" class="itemsContainer vertical-wrap centered"></div>
</div>
<div class="readOnlyContent" style="margin: .5em auto 1em;">
<button is="emby-button" type="button" class="raised cancel block btnManual">
<span>${ButtonManualLogin}</span>
</button>
<button is="emby-button" type="button" class="raised cancel block btnForgotPassword">
<span>${ButtonForgotPassword}</span>
</button>
<button is="emby-button" type="button" class="raised block btnSelectServer">
<span>${ButtonChangeServer}</span>
</button>
<p class="disclaimer" style="text-align: center; margin-top: 2em;"></p>
</div>
</div>
</div>

View file

@ -0,0 +1,227 @@
import appHost from 'apphost';
import appSettings from 'appSettings';
import dom from 'dom';
import connectionManager from 'connectionManager';
import loading from 'loading';
import layoutManager from 'layoutManager';
import libraryMenu from 'libraryMenu';
import browser from 'browser';
import globalize from 'globalize';
import 'cardStyle';
import 'emby-checkbox';
/* eslint-disable indent */
const enableFocusTransform = !browser.slow && !browser.edge;
function authenticateUserByName(page, apiClient, username, password) {
loading.show();
apiClient.authenticateUserByName(username, password).then(function (result) {
var user = result.User;
loading.hide();
Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient);
Dashboard.navigate('home.html');
}, function (response) {
page.querySelector('#txtManualName').value = '';
page.querySelector('#txtManualPassword').value = '';
loading.hide();
const UnauthorizedOrForbidden = [401, 403];
if (UnauthorizedOrForbidden.includes(response.status)) {
import('toast').then(({default: toast}) => {
const messageKey = response.status === 401 ? 'MessageInvalidUser' : 'MessageUnauthorizedUser';
toast(globalize.translate(messageKey));
});
} else {
Dashboard.alert({
message: globalize.translate('MessageUnableToConnectToServer'),
title: globalize.translate('HeaderConnectionFailure')
});
}
});
}
function showManualForm(context, showCancel, focusPassword) {
context.querySelector('.chkRememberLogin').checked = appSettings.enableAutoLogin();
context.querySelector('.manualLoginForm').classList.remove('hide');
context.querySelector('.visualLoginForm').classList.add('hide');
context.querySelector('.btnManual').classList.add('hide');
if (focusPassword) {
context.querySelector('#txtManualPassword').focus();
} else {
context.querySelector('#txtManualName').focus();
}
if (showCancel) {
context.querySelector('.btnCancel').classList.remove('hide');
} else {
context.querySelector('.btnCancel').classList.add('hide');
}
}
const metroColors = ['#6FBD45', '#4BB3DD', '#4164A5', '#E12026', '#800080', '#E1B222', '#008040', '#0094FF', '#FF00C7', '#FF870F', '#7F0037'];
function getRandomMetroColor() {
const index = Math.floor(Math.random() * (metroColors.length - 1));
return metroColors[index];
}
function getMetroColor(str) {
if (str) {
const character = String(str.substr(0, 1).charCodeAt());
let sum = 0;
for (let i = 0; i < character.length; i++) {
sum += parseInt(character.charAt(i));
}
const index = String(sum).substr(-1);
return metroColors[index];
}
return getRandomMetroColor();
}
function loadUserList(context, apiClient, users) {
let html = '';
for (let i = 0; i < users.length; i++) {
const user = users[i];
// TODO move card creation code to Card component
let cssClass = 'card squareCard scalableCard squareCard-scalable';
if (layoutManager.tv) {
cssClass += ' show-focus';
if (enableFocusTransform) {
cssClass += ' show-animation';
}
}
const cardBoxCssClass = 'cardBox cardBox-bottompadded';
html += '<button type="button" class="' + cssClass + '">';
html += '<div class="' + cardBoxCssClass + '">';
html += '<div class="cardScalable">';
html += '<div class="cardPadder cardPadder-square"></div>';
html += '<div class="cardContent" data-haspw="' + user.HasPassword + '" data-username="' + user.Name + '" data-userid="' + user.Id + '">';
let imgUrl;
if (user.PrimaryImageTag) {
imgUrl = apiClient.getUserImageUrl(user.Id, {
width: 300,
tag: user.PrimaryImageTag,
type: 'Primary'
});
html += '<div class="cardImageContainer coveredImage coveredImage-noScale" style="background-image:url(\'' + imgUrl + "');\"></div>";
} else {
const background = getMetroColor(user.Id);
imgUrl = 'assets/img/avatar.png';
html += '<div class="cardImageContainer coveredImage coveredImage-noScale" style="background-image:url(\'' + imgUrl + "');background-color:" + background + ';"></div>';
}
html += '</div>';
html += '</div>';
html += '<div class="cardFooter visualCardBox-cardFooter">';
html += '<div class="cardText singleCardText cardTextCentered">' + user.Name + '</div>';
html += '</div>';
html += '</div>';
html += '</button>';
}
context.querySelector('#divUsers').innerHTML = html;
}
export default function (view, params) {
function getApiClient() {
const serverId = params.serverid;
if (serverId) {
return connectionManager.getOrCreateApiClient(serverId);
}
return ApiClient;
}
function showVisualForm() {
view.querySelector('.visualLoginForm').classList.remove('hide');
view.querySelector('.manualLoginForm').classList.add('hide');
view.querySelector('.btnManual').classList.remove('hide');
import('autoFocuser').then(({default: autoFocuser}) => {
autoFocuser.autoFocus(view);
});
}
view.querySelector('#divUsers').addEventListener('click', function (e) {
const card = dom.parentWithClass(e.target, 'card');
const cardContent = card ? card.querySelector('.cardContent') : null;
if (cardContent) {
const context = view;
const id = cardContent.getAttribute('data-userid');
const name = cardContent.getAttribute('data-username');
const haspw = cardContent.getAttribute('data-haspw');
if (id === 'manual') {
context.querySelector('#txtManualName').value = '';
showManualForm(context, true);
} else if (haspw == 'false') {
authenticateUserByName(context, getApiClient(), name, '');
} else {
context.querySelector('#txtManualName').value = name;
context.querySelector('#txtManualPassword').value = '';
showManualForm(context, true, true);
}
}
});
view.querySelector('.manualLoginForm').addEventListener('submit', function (e) {
appSettings.enableAutoLogin(view.querySelector('.chkRememberLogin').checked);
const apiClient = getApiClient();
authenticateUserByName(view, apiClient, view.querySelector('#txtManualName').value, view.querySelector('#txtManualPassword').value);
e.preventDefault();
return false;
});
view.querySelector('.btnForgotPassword').addEventListener('click', function () {
Dashboard.navigate('forgotpassword.html');
});
view.querySelector('.btnCancel').addEventListener('click', showVisualForm);
view.querySelector('.btnManual').addEventListener('click', function () {
view.querySelector('#txtManualName').value = '';
showManualForm(view, true);
});
view.querySelector('.btnSelectServer').addEventListener('click', function () {
Dashboard.selectServer();
});
view.addEventListener('viewshow', function (e) {
loading.show();
libraryMenu.setTransparentMenu(true);
if (!appHost.supports('multiserver')) {
view.querySelector('.btnSelectServer').classList.add('hide');
}
const apiClient = getApiClient();
apiClient.getPublicUsers().then(function (users) {
if (users.length) {
showVisualForm();
loadUserList(view, apiClient, users);
} else {
view.querySelector('#txtManualName').value = '';
showManualForm(view, false, false);
}
}).catch().then(function () {
loading.hide();
});
apiClient.getJSON(apiClient.getUrl('Branding/Configuration')).then(function (options) {
view.querySelector('.disclaimer').textContent = options.LoginDisclaimer || '';
});
});
view.addEventListener('viewhide', function (e) {
libraryMenu.setTransparentMenu(false);
});
}
/* eslint-enable indent */

View file

@ -0,0 +1,23 @@
<div data-role="page" class="page standalonePage forgotPasswordPinPage">
<div class="padded-left padded-right padded-bottom-page">
<form class="forgotPasswordPinForm" style="text-align: center; margin: 0 auto;">
<div style="text-align: left;">
<h2>${HeaderPasswordReset}</h2>
<div class="inputContainer">
<input is="emby-input" type="text" id="txtPin" label="${LabelPasswordRecoveryPinCode}" autocomplete="off" required="required"/>
</div>
<div>
<button is="emby-button" type="submit" class="raised submit block">
<span>${ButtonSubmit}</span>
</button>
<button is="emby-button" type="button" class="raised cancel block btnCancel" onclick="history.back();">
<span>${ButtonCancel}</span>
</button>
</div>
</div>
</form>
</div>
</div>

View file

@ -0,0 +1,43 @@
import globalize from 'globalize';
/* eslint-disable indent */
function processForgotPasswordResult(result) {
if (result.Success) {
let msg = globalize.translate('MessagePasswordResetForUsers');
msg += '<br/>';
msg += '<br/>';
msg += result.UsersReset.join('<br/>');
return void Dashboard.alert({
message: msg,
title: globalize.translate('HeaderPasswordReset'),
callback: function () {
window.location.href = 'index.html';
}
});
}
Dashboard.alert({
message: globalize.translate('MessageInvalidForgotPasswordPin'),
title: globalize.translate('HeaderPasswordReset')
});
}
export default function (view, params) {
function onSubmit(e) {
ApiClient.ajax({
type: 'POST',
url: ApiClient.getUrl('Users/ForgotPassword/Pin'),
dataType: 'json',
data: {
Pin: view.querySelector('#txtPin').value
}
}).then(processForgotPasswordResult);
e.preventDefault();
return false;
}
view.querySelector('form').addEventListener('submit', onSubmit);
}
/* eslint-enable indent */

View file

@ -0,0 +1,17 @@
<div id="selectServerPage" data-role="page" class="page noSecondaryNavPage standalonePage pageContainer fullWidthContent vertical flex flex-direction-column">
<div class="margin-auto-y">
<div class="verticalSection flex-shrink-zero w-100 flex flex-direction-column">
<div class="padded-left padded-right flex align-items-center justify-content-center">
<h1 class="sectionTitle sectionTitle-cards">${HeaderSelectServer}</h1>
</div>
<div class="padded-top padded-bottom-focusscale flex-grow flex" data-horizontal="true" data-centerfocus="card">
<div is="emby-itemscontainer" class="scrollSlider focuscontainer-x servers flex-grow" style="display: block; text-align: center;" data-hovermenu="false" data-multiselect="false"></div>
</div>
</div>
<div class="padded-top padded-left padded-right flex flex-shrink-zero justify-content-center verticalSection flex-wrap-wrap margin-auto-x">
<a is="emby-linkbutton" href="addserver.html" class="raised cancel btnAddServer flex-shrink-zero" style="margin: .25em;">
<span>${ButtonAddServer}</span>
</a>
</div>
</div>
</div>

View file

@ -0,0 +1,228 @@
import loading from 'loading';
import appRouter from 'appRouter';
import layoutManager from 'layoutManager';
import libraryMenu from 'libraryMenu';
import appSettings from 'appSettings';
import appHost from 'apphost';
import focusManager from 'focusManager';
import connectionManager from 'connectionManager';
import globalize from 'globalize';
import actionSheet from 'actionsheet';
import dom from 'dom';
import browser from 'browser';
import 'material-icons';
import 'flexStyles';
import 'emby-scroller';
import 'emby-itemscontainer';
import 'cardStyle';
import 'emby-button';
/* eslint-disable indent */
const enableFocusTransform = !browser.slow && !browser.edge;
function renderSelectServerItems(view, servers) {
const items = servers.map(function (server) {
return {
name: server.Name,
showIcon: true,
icon: 'cast',
cardType: '',
id: server.Id,
server: server
};
});
let html = items.map(function (item) {
let cardImageContainer;
if (item.showIcon) {
cardImageContainer = '<span class="cardImageIcon material-icons ' + item.icon + '"></span>';
} else {
cardImageContainer = '<div class="cardImage" style="' + item.cardImageStyle + '"></div>';
}
// TODO move card creation code to Card component
let cssClass = 'card overflowSquareCard loginSquareCard scalableCard overflowSquareCard-scalable';
if (layoutManager.tv) {
cssClass += ' show-focus';
if (enableFocusTransform) {
cssClass += ' show-animation';
}
}
const cardBoxCssClass = 'cardBox';
const innerOpening = '<div class="' + cardBoxCssClass + '">';
let cardContainer = '';
cardContainer += '<button raised class="' + cssClass + '" style="display:inline-block;" data-id="' + item.id + '" data-url="' + (item.url || '') + '" data-cardtype="' + item.cardType + '">';
cardContainer += innerOpening;
cardContainer += '<div class="cardScalable">';
cardContainer += '<div class="cardPadder cardPadder-square">';
cardContainer += '</div>';
cardContainer += '<div class="cardContent">';
cardContainer += '<div class="cardImageContainer coveredImage" style="background:#0288D1;border-radius:.15em;">';
cardContainer += cardImageContainer;
cardContainer += '</div>';
cardContainer += '</div>';
cardContainer += '</div>';
cardContainer += '<div class="cardFooter">';
cardContainer += '<div class="cardText cardTextCentered">' + item.name + '</div>';
cardContainer += '</div></div></button>';
return cardContainer;
}).join('');
const itemsContainer = view.querySelector('.servers');
if (!items.length) {
html = '<p>' + globalize.translate('MessageNoServersAvailable') + '</p>';
}
itemsContainer.innerHTML = html;
loading.hide();
}
function updatePageStyle(view, params) {
if (params.showuser == '1') {
view.classList.add('libraryPage');
view.classList.remove('standalonePage');
view.classList.add('noSecondaryNavPage');
} else {
view.classList.add('standalonePage');
view.classList.remove('libraryPage');
view.classList.remove('noSecondaryNavPage');
}
}
function showGeneralError() {
loading.hide();
alertText(globalize.translate('DefaultErrorMessage'));
}
function alertText(text) {
alertTextWithOptions({
text: text
});
}
function alertTextWithOptions(options) {
import('alert').then(({default: alert}) => {
alert(options);
});
}
function showServerConnectionFailure() {
alertText(globalize.translate('MessageUnableToConnectToServer'));
}
export default function (view, params) {
function connectToServer(server) {
loading.show();
connectionManager.connectToServer(server, {
enableAutoLogin: appSettings.enableAutoLogin()
}).then(function (result) {
loading.hide();
const apiClient = result.ApiClient;
switch (result.State) {
case 'SignedIn':
Dashboard.onServerChanged(apiClient.getCurrentUserId(), apiClient.accessToken(), apiClient);
Dashboard.navigate('home.html');
break;
case 'ServerSignIn':
Dashboard.onServerChanged(null, null, apiClient);
Dashboard.navigate('login.html?serverid=' + result.Servers[0].Id);
break;
case 'ServerUpdateNeeded':
alertTextWithOptions({
text: globalize.translate('core#ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin'),
html: globalize.translate('core#ServerUpdateNeeded', '<a href="https://github.com/jellyfin/jellyfin">https://github.com/jellyfin/jellyfin</a>')
});
break;
default:
showServerConnectionFailure();
}
});
}
function deleteServer(server) {
loading.show();
connectionManager.deleteServer(server.Id).then(function () {
loading.hide();
loadServers();
});
}
function onServerClick(server) {
const menuItems = [];
menuItems.push({
name: globalize.translate('Connect'),
id: 'connect'
});
menuItems.push({
name: globalize.translate('Delete'),
id: 'delete'
});
actionSheet.show({
items: menuItems,
title: server.Name
}).then(function (id) {
switch (id) {
case 'connect':
connectToServer(server);
break;
case 'delete':
deleteServer(server);
}
});
}
function onServersRetrieved(result) {
servers = result;
renderSelectServerItems(view, result);
if (layoutManager.tv) {
focusManager.autoFocus(view);
}
}
function loadServers() {
loading.show();
connectionManager.getAvailableServers().then(onServersRetrieved);
}
let servers;
updatePageStyle(view, params);
view.addEventListener('viewshow', function (e) {
const isRestored = e.detail.isRestored;
appRouter.setTitle(null);
libraryMenu.setTransparentMenu(true);
if (!isRestored) {
loadServers();
}
});
view.querySelector('.servers').addEventListener('click', function (e) {
const card = dom.parentWithClass(e.target, 'card');
if (card) {
const url = card.getAttribute('data-url');
if (url) {
appRouter.show(url);
} else {
const id = card.getAttribute('data-id');
onServerClick(servers.filter(function (s) {
return s.Id === id;
})[0]);
}
}
});
}
/* eslint-enable indent */