Accessibility enhancements: catching a11y errors with WAVE (#180)
* Added alt text for all images * Added aria labels for most buttons that needed them. Added html language label * Added remaining button labels * Added remaining missing labels. Tagged <input> where labels made no sense as "aria-hidden=true" * Fixed some of the low color contrast issues for Light theme * Replaced broken ARIA link with a new ARIA label * Fixed skipped heading levels * Fixed missing fieldset and one orphaned label (combined the two) * Changed the other orphaned label to a fieldset legend * Removed color changes * Added dynamic ARIA label for main Play/Pause button. Removed the two FIXMEs in index.html * Added default content to table header * Changed input type from text to hidden for hidden inputs * Added proper alt text for cover art * Final version of the template row * Added semantic markup to Page Regions * Missing alt text + truncated alt text - Added missing alt text for cover images in library and floating player. - Added JS to truncate alt text for cover images that was too long. * Sanitize the code Co-authored-by: Terry Geng <terry@terriex.com>
This commit is contained in:
parent
fd009eabe8
commit
e981782dd7
File diff suppressed because one or more lines are too long
@ -10,6 +10,7 @@ import {
|
||||
isOverflown,
|
||||
setProgressBar,
|
||||
secondsToStr,
|
||||
coverArtString,
|
||||
} from './util';
|
||||
|
||||
$('#uploadSelectFile').on('change', function () {
|
||||
@ -123,6 +124,7 @@ function addPlaylistItem(item) {
|
||||
pl_title_element.html(item.title);
|
||||
pl_artist_element.html(item.artist);
|
||||
pl_thumb_element.attr('src', item.thumbnail);
|
||||
pl_thumb_element.attr('alt', coverArtString(item.title));
|
||||
pl_type_element.html(item.type);
|
||||
pl_path_element.html(item.path);
|
||||
|
||||
@ -323,9 +325,15 @@ function updateControls(empty, play, mode, volume) {
|
||||
if (play) {
|
||||
playing = true;
|
||||
playPauseBtn.find('[data-fa-i2svg]').removeClass('fa-play').addClass('fa-pause');
|
||||
// PR #180: Since this button changes behavior dynamically, we change its
|
||||
// ARIA labels in JS instead of only adding them statically in the HTML
|
||||
playPauseBtn.attr('aria-label', 'Pause');
|
||||
} else {
|
||||
playing = false;
|
||||
playPauseBtn.find('[data-fa-i2svg]').removeClass('fa-pause').addClass('fa-play');
|
||||
// PR #180: Since this button changes behavior dynamically, we change its
|
||||
// ARIA labels in JS instead of only adding them statically in the HTML
|
||||
playPauseBtn.attr('aria-label', 'Play');
|
||||
}
|
||||
}
|
||||
|
||||
@ -510,6 +518,7 @@ function addResultItem(item) {
|
||||
title_element.html(item.title);
|
||||
artist_element.html(item.artist ? ('- ' + item.artist) : '');
|
||||
thumb_element.attr('src', item.thumb);
|
||||
thumb_element.attr('alt', coverArtString(item.title));
|
||||
type_element.html('[' + item.type + ']');
|
||||
path_element.html(item.path);
|
||||
|
||||
@ -1111,6 +1120,7 @@ function updatePlayerInfo(item) {
|
||||
playerTitle.textContent = item.title;
|
||||
playerArtist.textContent = item.artist;
|
||||
playerArtwork.setAttribute('src', item.thumbnail);
|
||||
playerArtwork.setAttribute('alt', coverArtString(item.title));
|
||||
|
||||
if (isOverflown(playerTitle)) {
|
||||
playerTitle.classList.add('scrolling');
|
||||
|
@ -16,3 +16,20 @@ export function secondsToStr(seconds) {
|
||||
const secs = seconds % 60;
|
||||
return ('00' + mins).slice(-2) + ':' + ('00' + secs).slice(-2);
|
||||
}
|
||||
|
||||
export function coverArtString(title) {
|
||||
|
||||
let nameOfSong = "";
|
||||
// The maximum length before we start truncating
|
||||
const maxLength = 50;
|
||||
|
||||
if (title.length > maxLength) {
|
||||
// Name = longTitleTooLongToBeAGoodAltTex...
|
||||
nameOfSong = title.substr(0, maxLength) + "\u2026";
|
||||
} else {
|
||||
// Name = shortTitle
|
||||
nameOfSong = title;
|
||||
}
|
||||
|
||||
return 'Cover art for ' + nameOfSong;
|
||||
}
|
@ -1,46 +1,59 @@
|
||||
.btn-space {margin-right: 5px;}
|
||||
.btn-space {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Playlist */
|
||||
.playlist-item {transition: all 0.2s ease-in-out;}
|
||||
.playlist-item {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.playlist-artwork {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tag-space {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.tag-click {
|
||||
cursor: pointer;
|
||||
transition: 400ms;
|
||||
}
|
||||
|
||||
.tag-unclicked {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.tag-clicked {
|
||||
box-shadow: 2px 4px 10px #777777;
|
||||
transform: scale(1.2);
|
||||
opacity: 1;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.library-item {
|
||||
display: flex;
|
||||
padding: .5rem .5rem .5rem 0;
|
||||
height: 72px;
|
||||
transition: ease-in-out 200ms;
|
||||
}
|
||||
|
||||
.library-thumb-img {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.library-thumb-col {
|
||||
position: relative;
|
||||
padding-left: 0;
|
||||
overflow: hidden;
|
||||
margin: -0.5rem 1rem -0.5rem 0;
|
||||
}
|
||||
|
||||
.library-thumb-grp {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -52,9 +65,11 @@
|
||||
opacity: 0.7;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.library-thumb-grp-hover {
|
||||
left: -15px;
|
||||
}
|
||||
|
||||
.library-thumb-btn-up {
|
||||
position: absolute !important;
|
||||
top: 0;
|
||||
@ -62,10 +77,12 @@
|
||||
font-size: 2em;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.library-btn-svg {
|
||||
width: 1rem;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.library-info-col {
|
||||
margin-right: 1rem;
|
||||
padding: 3px 0;
|
||||
@ -75,12 +92,15 @@
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.library-info-col .small {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.library-action {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.library-info-col .path {
|
||||
font-style: italic !important;
|
||||
font-weight: 300;
|
||||
@ -101,17 +121,21 @@
|
||||
position: fixed;
|
||||
right: 50px;
|
||||
}
|
||||
|
||||
.floating-button:hover {
|
||||
background-color: hsl(0, 0%, 43%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
#volume-slider {
|
||||
margin-top: 4px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#volume-popover {
|
||||
position: relative;
|
||||
background: #333;
|
||||
@ -122,12 +146,15 @@
|
||||
border-radius: 4px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#volume-popover[data-show] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#volume-popover a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#volume-popover-arrow,
|
||||
#volume-popover-arrow::before {
|
||||
position: absolute;
|
||||
@ -143,24 +170,29 @@
|
||||
transform: rotate(45deg);
|
||||
background: #333;
|
||||
}
|
||||
|
||||
#volume-popover[data-popper-placement^='top']>#volume-popover-arrow {
|
||||
bottom: -4px;
|
||||
}
|
||||
|
||||
#playerToast {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
#playerContainer {
|
||||
display: flex;
|
||||
height: 105px;
|
||||
}
|
||||
|
||||
#playerArtwork {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#playerArtworkIdle {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
@ -168,6 +200,7 @@
|
||||
margin: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#playerInfo {
|
||||
position: relative;
|
||||
padding-top: 6px;
|
||||
@ -175,40 +208,58 @@
|
||||
height: 80px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#playerTitle {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#playerArtist {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
#playerActionBox {
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#playerBarBox {
|
||||
margin-top: 5px;
|
||||
height: 15px;
|
||||
width: 400px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scrolling {
|
||||
animation: scrolling 8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes scrolling {
|
||||
0% {
|
||||
transform: translateX(100%);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
95% {
|
||||
transform: translateX(-90%);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Allows us to have H3 with the size of an H5
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
// Makes legend match the size of other labels
|
||||
legend {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta charset="UTF-8">
|
||||
@ -12,28 +14,31 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container page-header mb-5" id="banner">
|
||||
<header class="container page-header mb-5" id="banner">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<img src="static/image/logo.png" height="200px">
|
||||
<img src="static/image/logo.png" height="200px"
|
||||
alt="Botamusique Logo: a person with two headphones, enjoying the music">
|
||||
</div>
|
||||
<div class="col my-auto">
|
||||
<h1>botamusique Web Interface</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="playlist" class="container mb-5">
|
||||
<main id="playlist" class="container mb-5">
|
||||
<div class="btn-toolbar mb-2" role="toolbar" aria-label="Playlist controls">
|
||||
<button type="button" id="play-pause-btn" class="btn btn-info mb-2 btn-space">
|
||||
<button type="button" id="play-pause-btn" class="btn btn-info mb-2 btn-space" aria-label="Play">
|
||||
<i class="fas fa-play"></i>
|
||||
</button>
|
||||
<button type="button" id="fast-forward-btn" class="btn btn-info mb-2">
|
||||
<button type="button" id="fast-forward-btn" class="btn btn-info mb-2" aria-label="Skip Track">
|
||||
<i class="fas fa-fast-forward"></i>
|
||||
</button>
|
||||
<div class="ml-auto">
|
||||
<div class="dropdown mr-2">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="play-mode" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="play-mode"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
|
||||
aria-label="Change Playback Mode">
|
||||
<i class="fas fa-tasks mr-2" aria-hidden="true" id="modeIndicator"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="play-mode">
|
||||
@ -51,7 +56,8 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="volume-popover-btn" class="btn btn-warning ml-1">
|
||||
<button type="button" id="volume-popover-btn" class="btn btn-warning ml-1"
|
||||
aria-label="Open Volume Controls">
|
||||
<i class="fa fa-volume-up" aria-hidden="true"></i>
|
||||
</button>
|
||||
|
||||
@ -60,7 +66,8 @@
|
||||
<i class="fa fa-volume-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
|
||||
<input type="range" class="custom-range ml-1" id="volume-slider" min="0" max="1" step="0.01" value="0.5" />
|
||||
<input type="range" class="custom-range ml-1" id="volume-slider" min="0" max="1" step="0.01"
|
||||
value="0.5" aria-label="Volume Slider" />
|
||||
|
||||
<a id="volume-up-btn">
|
||||
<i class="fa fa-volume-up" aria-hidden="true"></i>
|
||||
@ -83,25 +90,29 @@
|
||||
<tbody id="playlist-table" class="playlist-table">
|
||||
<tr id="playlist-loading">
|
||||
<td colspan="4" class="text-center">
|
||||
<img style="margin: auto; width: 35px;" src="static/image/loading.svg" />
|
||||
<img style="margin: auto; width: 35px;" src="static/image/loading.svg"
|
||||
alt="A loading spinner" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="playlist-empty" class="d-none">
|
||||
<td colspan="4" class="text-center">
|
||||
<img style="margin: auto; width: 35px;" src="static/image/empty_box.svg" />
|
||||
<img style="margin: auto; width: 35px;" src="static/image/empty_box.svg"
|
||||
alt="A drawing of an empty box." />
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="playlist-expand table-dark d-none">
|
||||
<td colspan="4" class="text-center">
|
||||
<a class="text-muted" href="javascript:">See item <span class="playlist-expand-item-range"></span> on the playlist.</a>
|
||||
<a class="text-muted" href="javascript:">See item <span
|
||||
class="playlist-expand-item-range"></span> on the playlist.</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="playlist-item-template d-none">
|
||||
<th scope="row" class="playlist-item-index d-none d-md-table-cell"></th>
|
||||
<tr class="playlist-item-template d-none" aria-hidden="true">
|
||||
<th scope="row" class="playlist-item-index d-none d-md-table-cell">1</th>
|
||||
<td>
|
||||
<input hidden type="text" class="playlist-item-id" value="" />
|
||||
<input hidden type="hidden" class="playlist-item-id" value="" />
|
||||
<div class="float-left">
|
||||
<img width="80" class="playlist-item-thumbnail" src="static/image/unknown-album.png" />
|
||||
<img width="80" class="playlist-item-thumbnail" src="static/image/unknown-album.png"
|
||||
alt="A black square with two eight notes beamed together." />
|
||||
</div>
|
||||
<div class="playlist-artwork">
|
||||
<b class="playlist-item-title"></b>
|
||||
@ -122,10 +133,12 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="playlist-item-play btn btn-info btn-sm">
|
||||
<button type="button" class="playlist-item-play btn btn-info btn-sm"
|
||||
aria-label="Skip current song and play this song right now">
|
||||
<i class="fas fa-play" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button type="button" class="playlist-item-trash btn btn-danger btn-sm ml-1">
|
||||
<button type="button" class="playlist-item-trash btn btn-danger btn-sm ml-1"
|
||||
aria-label="Remove this song from the current playlist">
|
||||
<i class="fas fa-trash-alt" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
@ -140,19 +153,19 @@
|
||||
<i class="fas fa-trash-alt" aria-hidden="true"></i> Clear Playlist
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container mb-3">
|
||||
<h2 id="forms">Music Library</h2>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Filters</h5>
|
||||
<h3 class="card-title">Filters</h3>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label>Type</label>
|
||||
<div id="filter-type" class="input-group mb-2">
|
||||
<fieldset id="filter-type" class="mb-2">
|
||||
<legend>Type</legend>
|
||||
<div class="btn-group btn-group-sm btn-group-toggle">
|
||||
<label id="filter-type-file" class="btn btn-secondary">
|
||||
<input type="checkbox" name="options"> File
|
||||
@ -164,7 +177,7 @@
|
||||
<input type="checkbox" name="options"> Radio
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<label for="filter-dir">Directory</label>
|
||||
<div id="filter-path" class="input-group mb-2">
|
||||
@ -178,34 +191,39 @@
|
||||
|
||||
<label for="filter-keywords">Keywords</label>
|
||||
<div id="filter-path" class="input-group mb-2">
|
||||
<input class="form-control form-control-sm" id="filter-keywords" name="keywords" placeholder="Keywords..." style="margin-top:5px;" />
|
||||
<input class="form-control form-control-sm" id="filter-keywords" name="keywords"
|
||||
placeholder="Keywords..." style="margin-top:5px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<label for="filter-tag">Tags</label>
|
||||
<div id="filter-type mb-2">
|
||||
<fieldset id="filter-type mb-2">
|
||||
<legend>Tags</legend>
|
||||
{% for tag in tags_color_lookup.keys() %}
|
||||
<span id="filter-tag" class="filter-tag tag-unclicked tag-click badge badge-{{ tags_color_lookup[tag] }}">{{ tag }}</span>
|
||||
<span id="filter-tag"
|
||||
class="filter-tag tag-unclicked tag-click badge badge-{{ tags_color_lookup[tag] }}">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="library-group" class="list-group library-group" style="overflow: auto;">
|
||||
<div id="library-item-loading" class="list-group-item library-item">
|
||||
<img style="margin: auto; width: 35px;" src="static/image/loading.svg" />
|
||||
<img style="margin: auto; width: 35px;" src="static/image/loading.svg"
|
||||
alt="A loading spinner" />
|
||||
</div>
|
||||
<div id="library-item-empty" style="display: none" class="list-group-item library-item">
|
||||
<img style="margin: auto; width: 35px;" src="static/image/empty_box.svg" />
|
||||
<img style="margin: auto; width: 35px;" src="static/image/empty_box.svg"
|
||||
alt="A drawing of an empty box." />
|
||||
</div>
|
||||
<div id="library-item" style="display: none;" class="list-group-item library-item">
|
||||
<input hidden type="text" class="library-item-id" value="" />
|
||||
<input hidden type="hidden" class="library-item-id" value="" />
|
||||
|
||||
<div class="library-thumb-col">
|
||||
<div class="library-thumb-img">
|
||||
<img class="library-item-thumb library-thumb-img" src="static/image/unknown-album.png" />
|
||||
<img class="library-item-thumb library-thumb-img" src="static/image/unknown-album.png"
|
||||
alt="A black square with two eight notes beamed together." />
|
||||
</div>
|
||||
<div class="btn-group-vertical library-thumb-grp">
|
||||
<div class="library-item-play btn btn-secondary library-thumb-btn-up" title="Play">
|
||||
@ -225,28 +243,40 @@
|
||||
<div class="library-info-col col-4 d-none d-md-flex" style="padding: 3px;">
|
||||
<span class="library-item-path text-muted path">Path/to/the/file</span>
|
||||
<div class="library-item-tags">
|
||||
<a class="tag-space tag-click library-item-edit"><i class="fas fa-edit" style="color: #AAAAAA"></i></a>
|
||||
<a class="tag-space tag-click library-item-edit"><i class="fas fa-edit"
|
||||
style="color: #AAAAAA"></i></a>
|
||||
<span class="library-item-notag badge badge-light text-muted font-italic">No tag</span>
|
||||
<span class="library-item-tag tag-space badge">Tag</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group library-action">
|
||||
<button class="library-item-add-next btn btn-info btn-sm btn-space" type="button" title="Next to play">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;" viewBox="5 5 17 17">
|
||||
<path d="m5.700245,3.92964l0,14.150376l11.451127,-7.075188l-11.451127,-7.075188z"></path>
|
||||
<path d="m20.942859,18.221072l-3.323292,0l0,3.323292l-1.107764,0l0,-3.323292l-3.323292,0l0,-1.107764l3.323292,0l0,-3.323292l1.107764,0l0,3.323292l3.323292,0l0,1.107764z"></path>
|
||||
<button class="library-item-add-next btn btn-info btn-sm btn-space" type="button"
|
||||
title="Next to play" aria-label="Add to playlist right after current song">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;"
|
||||
viewBox="5 5 17 17">
|
||||
<path d="m5.700245,3.92964l0,14.150376l11.451127,-7.075188l-11.451127,-7.075188z">
|
||||
</path>
|
||||
<path
|
||||
d="m20.942859,18.221072l-3.323292,0l0,3.323292l-1.107764,0l0,-3.323292l-3.323292,0l0,-1.107764l3.323292,0l0,-3.323292l1.107764,0l0,3.323292l3.323292,0l0,1.107764z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="library-item-add-bottom library-btn btn btn-info btn-sm btn-space" type="button" title="Add to bottom">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;" viewBox="2 2 20 20">
|
||||
<path d="M2,16H10V14H2M18,14V10H16V14H12V16H16V20H18V16H22V14M14,6H2V8H14M14,10H2V12H14V10Z"></path>
|
||||
<button class="library-item-add-bottom library-btn btn btn-info btn-sm btn-space"
|
||||
type="button" title="Add to bottom" aria-label="Add to bottom of current playlist">
|
||||
<svg class="library-btn-svg" style="width: 1rem; fill: currentColor;"
|
||||
viewBox="2 2 20 20">
|
||||
<path
|
||||
d="M2,16H10V14H2M18,14V10H16V14H12V16H16V20H18V16H22V14M14,6H2V8H14M14,10H2V12H14V10Z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="library-item-download btn btn-primary btn-sm btn-space" type="button">
|
||||
<button class="library-item-download btn btn-primary btn-sm btn-space" type="button"
|
||||
aria-label="Download song from library">
|
||||
<i class="fas fa-download" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button class="library-item-trash btn btn-danger btn-sm btn-space" type="button">
|
||||
<button class="library-item-trash btn btn-danger btn-sm btn-space" type="button"
|
||||
aria-label="Remove song from library">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
@ -274,16 +304,19 @@
|
||||
<button id="library-download-btn" type="button" class="btn btn-secondary mr-1">
|
||||
<i class="fas fa-download" aria-hidden="true"></i> Download All
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger mr-1" data-toggle="modal" data-target="#deleteWarningModal">
|
||||
<button type="button" class="btn btn-danger mr-1" data-toggle="modal"
|
||||
data-target="#deleteWarningModal">
|
||||
<i class="fas fa-trash-alt" aria-hidden="true"></i> Delete All
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="deleteWarningModal" tabindex="-1" role="dialog" aria-labelledby="Warning-Delete-File" aria-hidden="true">
|
||||
<!-- QUESTION: should this div have aria-hidden as true?? -->
|
||||
<div class="modal fade" id="deleteWarningModal" tabindex="-1" role="dialog"
|
||||
aria-label="Modal Window for warning about deletion of files." aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteWarningModalLabel">Are you really sure?</h5>
|
||||
<h3 class="modal-title" id="deleteWarningModalLabel">Are you really sure?</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
@ -295,7 +328,8 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button id="library-delete-btn" type="button" class="btn btn-danger" data-dismiss="modal">Delete All Listed Files</button>
|
||||
<button id="library-delete-btn" type="button" class="btn btn-danger"
|
||||
data-dismiss="modal">Delete All Listed Files</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -304,7 +338,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- beautify ignore:start -->
|
||||
{% if upload_enabled %}
|
||||
<div id="upload" class="container mb-3">
|
||||
{% else %}
|
||||
@ -313,7 +346,7 @@
|
||||
{% endif %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Upload File</h5>
|
||||
<h3 class="card-title">Upload File</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="./upload" method="post" enctype="multipart/form-data">
|
||||
@ -333,7 +366,7 @@
|
||||
<div class="col">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Upload To</span>
|
||||
<label for="uploadTargetDir" class="input-group-text">Upload To</label>
|
||||
</div>
|
||||
<input class="form-control" list="targetdirs" id="uploadTargetDir" name="targetdir" placeholder="uploads" />
|
||||
<datalist id="targetdirs">
|
||||
@ -353,13 +386,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- beautify ignore:end -->
|
||||
|
||||
<div class="container mb-5">
|
||||
<div class="card-deck">
|
||||
<div id="add-music-url" class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Add URL</h5>
|
||||
<h3 class="card-title">Add URL</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<label for="music-url-input">Add Youtube or Soundcloud URL</label>
|
||||
@ -373,7 +405,7 @@
|
||||
</div>
|
||||
<div id="add-radio-url" class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Add Radio</h5>
|
||||
<h3 class="card-title">Add Radio</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<label for="radio-url-input">Add Radio URL</label>
|
||||
@ -405,17 +437,20 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body" id="playerContainer">
|
||||
<img id="playerArtworkIdle" src="static/image/empty_box.svg" />
|
||||
<img id="playerArtwork" src="static/image/unknown-album.png" style="display: none;" />
|
||||
<img id="playerArtworkIdle" src="static/image/empty_box.svg" alt="A drawing of an empty box." />
|
||||
<img id="playerArtwork" src="static/image/unknown-album.png" style="display: none;"
|
||||
alt="A black square with two eight notes beamed together." />
|
||||
<div id="playerInfo">
|
||||
<div id="playerActionBox">
|
||||
<button id="playerPlayBtn" class="btn btn-primary btn-sm btn-space" style="display: none">
|
||||
<button id="playerPlayBtn" class="btn btn-primary btn-sm btn-space" style="display: none"
|
||||
aria-label="Play">
|
||||
<i class="fas fa-play"></i>
|
||||
</button>
|
||||
<button id="playerPauseBtn" class="btn btn-primary btn-sm btn-space" style="display: none">
|
||||
<button id="playerPauseBtn" class="btn btn-primary btn-sm btn-space" style="display: none"
|
||||
aria-label="Pause">
|
||||
<i class="fas fa-pause"></i>
|
||||
</button>
|
||||
<button id="playerSkipBtn" class="btn btn-primary btn-sm">
|
||||
<button id="playerSkipBtn" class="btn btn-primary btn-sm" aria-label="Skip to next track">
|
||||
<i class="fas fa-fast-forward"></i>
|
||||
</button>
|
||||
</div>
|
||||
@ -425,7 +460,9 @@
|
||||
</div>
|
||||
<span id="playerArtist">Artist</span>
|
||||
<div id="playerBarBox" class="progress">
|
||||
<div id="playerBar" class="progress-bar pr-2" role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" style="width: 100%; text-align: right; transform: translateX(-100%);"></div>
|
||||
<div id="playerBar" class="progress-bar pr-2" role="progressbar" aria-valuenow="50"
|
||||
aria-valuemin="0" aria-valuemax="100"
|
||||
style="width: 100%; text-align: right; transform: translateX(-100%);"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -434,33 +471,35 @@
|
||||
<div id="footer" style="height:50px; width: 100%; margin-top: 100px;"></div>
|
||||
|
||||
<form id="download-form" action="download" method="GET" target="_blank">
|
||||
<input hidden type="text" name="id" value="">
|
||||
<input hidden type="text" name="type" value="">
|
||||
<input hidden type="text" name="dir" value="">
|
||||
<input hidden type="text" name="tags" value="">
|
||||
<input hidden type="text" name="keywords" value="">
|
||||
<input hidden type="hidden" name="id" value="">
|
||||
<input hidden type="hidden" name="type" value="">
|
||||
<input hidden type="hidden" name="dir" value="">
|
||||
<input hidden type="hidden" name="tags" value="">
|
||||
<input hidden type="hidden" name="keywords" value="">
|
||||
</form>
|
||||
|
||||
<!-- Add tags modal -->
|
||||
<div class="modal fade" id="addTagModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal fade" id="addTagModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addTagModalTitle">Edit tags for ?</h5>
|
||||
<h3 class="modal-title" id="addTagModalTitle">Edit tags for ?</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="addTagModalBody" class="modal-body">
|
||||
<input hidden type="text" id="addTagModalItemId" name="id" value="">
|
||||
<input hidden type="hidden" id="addTagModalItemId" name="id" value="">
|
||||
<div class="modal-tag" style="display: none; width: 100%;">
|
||||
<span class="modal-tag-text tag-space badge badge-pill badge-dark">Tag</span>
|
||||
<a class="modal-tag-remove tag-click small"><i class="fas fa-times-circle btn-outline-danger"></i></a>
|
||||
<a class="modal-tag-remove tag-click small"><i
|
||||
class="fas fa-times-circle btn-outline-danger"></i></a>
|
||||
</div>
|
||||
<div id="addTagModalTags" style="margin-left: 5px; margin-bottom: 10px;">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input class="form-control form-control-sm btn-space" type="text" id="addTagModalInput" placeholder="tag1,tag2,...">
|
||||
<input class="form-control form-control-sm btn-space" type="text" id="addTagModalInput"
|
||||
placeholder="tag1,tag2,..." aria-label="Tags to add">
|
||||
<button id="addTagModalAddBtn" type="button" class="btn btn-primary btn-sm">
|
||||
<i class="fas fa-plus" aria-hidden="true"></i>
|
||||
Add
|
||||
@ -469,18 +508,19 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button id="addTagModalSubmit" type="button" class="btn btn-success" data-dismiss="modal">Edit!</button>
|
||||
<button id="addTagModalSubmit" type="button" class="btn btn-success"
|
||||
data-dismiss="modal">Edit!</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload files modal -->
|
||||
<div class="modal fade" id="uploadModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal fade" id="uploadModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="uploadTitle"><i class="fas fa-upload mr-1"></i>Uploading files...</h5>
|
||||
<h3 class="modal-title" id="uploadTitle"><i class="fas fa-upload mr-1"></i>Uploading files...</h3>
|
||||
</div>
|
||||
<div id="uploadModalBody" class="modal-body">
|
||||
<div id="uploadSuccessAlert" class="alert alert-success" role="alert" style="display: none">
|
||||
@ -493,7 +533,9 @@
|
||||
<span class="uploadItemTitle mr-3"></span>
|
||||
<span class="uploadItemError text-danger"></span>
|
||||
<div class="progress" style="margin-top: 5px; height: 10px;">
|
||||
<div class="uploadProgress progress-bar pr-2" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 100%; text-align: right; transform: translateX(-100%);"></div>
|
||||
<div class="uploadProgress progress-bar pr-2" role="progressbar" aria-valuenow="0"
|
||||
aria-valuemin="0" aria-valuemax="100"
|
||||
style="width: 100%; text-align: right; transform: translateX(-100%);"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -501,7 +543,9 @@
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="uploadClose" class="btn btn-success" data-dismiss="modal">
|
||||
<i class="fas fa-times mr-1"></i> Close</button>
|
||||
<button type="button" id="uploadCancel" class="btn btn-danger" data-toggle="tooltip" data-html="true" title="<strong>Are you really sure?</strong> <br /> Click again to abort uploading.">
|
||||
<button type="button" id="uploadCancel" class="btn btn-danger" data-toggle="tooltip"
|
||||
data-html="true"
|
||||
title="<strong>Are you really sure?</strong> <br /> Click again to abort uploading.">
|
||||
<i class="fas fa-trash-alt mr-1" aria-hidden="true"></i> Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user