Finished up with Playlist Managment UI.

This commit is contained in:
rainbow napkin 2025-04-04 08:18:20 -04:00
parent c8c59feb7f
commit f21b66fae0
7 changed files with 180 additions and 42 deletions

View file

@ -71,9 +71,28 @@ class playlistManager{
}
}
//Keeping everything in one function was super lazy when 'this.' exists, ESPECIALLY when writing a class!
//Really not sure what I was thinking here, this functions a bit of a stinker, and I'll probably re-write it sooner than later...
checkOpenPlaylists(){
//If open map is a string, indicating we just renamed a playlist with it's media open
if(typeof this.openMap == 'string'){
//Create new map to hold status with the new name of the renamed playlist already added
this.openMap = new Map([[this.openMap, true]]);
}else{
//Create new map to hold status
this.openMap = new Map();
}
//For each container Div rendered
for(let containerDiv of this.channelPlaylistDiv.querySelectorAll('.queue-playlist-media-container-div')){
//Set whether or not it's visible in the map
this.openMap.set(containerDiv.dataset['playlist'], (containerDiv.style.display != 'none'));
}
}
renderChannelPlaylists(data){
//Check for open playlists
this.checkOpenPlaylists();
//Clear channel playlist div
this.channelPlaylistDiv.innerHTML = '';
@ -87,9 +106,6 @@ class playlistManager{
//Set it's class
this.playlistDiv.classList.add('queue-playlist-div');
//Set playlist div dataset
this.playlistDiv.dataset.name = this.playlist.name;
//Create span to hold playlist entry line contents
this.playlistSpan = document.createElement('span');
//Set classes
@ -160,27 +176,7 @@ class playlistManager{
this.playlistLabels.appendChild(this.playlistCount);
//Define input listeners
this.playlistTitleSpan.addEventListener('click', toggleMedia.bind(this));
//I'd rather make this a class function but it's probably cleaner to not have to parent crawl
function toggleMedia(){
//If the div is hidden
if(this.mediaContainer.style.display == 'none'){
//Light up the button
this.playlistTitleSpan.classList.add('positive');
//Flip the caret
this.playlistTitleCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
//Show the div
this.mediaContainer.style.display = '';
}else{
//Unlight the button
this.playlistTitleSpan.classList.remove('positive');
//Flip the caret
this.playlistTitleCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
//Hide the div
this.mediaContainer.style.display = 'none';
}
}
this.playlistTitleSpan.addEventListener('click', this.toggleMedia.bind(this));
}
renderControls(){
@ -203,7 +199,7 @@ class playlistManager{
//Create queue all button
this.playlistQueueAllButton = document.createElement('button');
//Set it's classes
this.playlistQueueAllButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control');
this.playlistQueueAllButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control', 'not-first');
//Inject text content
this.playlistQueueAllButton.textContent = 'All';
//Set title
@ -212,7 +208,7 @@ class playlistManager{
//Create add from URL button
this.playlistAddURLButton = document.createElement('button');
//Set it's classes
this.playlistAddURLButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'positive-button');
this.playlistAddURLButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'positive-button', 'not-first');
//Set Tile
this.playlistAddURLButton.title = 'Add To Playlist From URL'
@ -223,13 +219,14 @@ class playlistManager{
this.playlistAddIcon.classList.add('bi-plus-lg');
this.playlistLinkIcon.classList.add('bi-link-45deg');
//Append icons to URL button
this.playlistAddURLButton.appendChild(this.playlistAddIcon);
this.playlistAddURLButton.appendChild(this.playlistLinkIcon);
//Create default titles button
this.playlistDefaultTitlesButton = document.createElement('button');
//Set classes
this.playlistDefaultTitlesButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-tags-fill', 'positive-button');
this.playlistDefaultTitlesButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-tags-fill', 'positive-button', 'not-first');
//Set title
this.playlistDefaultTitlesButton.title = 'Change Default Titles'
//Set dataset
@ -238,15 +235,14 @@ class playlistManager{
//Create rename button
this.playlistRenameButton = document.createElement('button');
//Set it's classes
this.playlistRenameButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-input-cursor-text', 'positive-button');
this.playlistRenameButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-input-cursor-text', 'positive-button', 'not-first');
//Set title
this.playlistRenameButton.title = 'Rename Playlist'
//Create delete button
this.playlistDeleteButton = document.createElement('button');
//Set it's classes
this.playlistDeleteButton.classList.add('queue-playlist-delete-button', 'queue-playlist-control', 'danger-button', 'bi-trash-fill');
this.playlistDeleteButton.classList.add('queue-playlist-delete-button', 'queue-playlist-control', 'danger-button', 'bi-trash-fill', 'not-first');
//Set title
this.playlistDeleteButton.title = 'Delete Playlist'
@ -271,8 +267,15 @@ class playlistManager{
this.mediaContainer = document.createElement('div');
//Set classes
this.mediaContainer.classList.add('queue-playlist-media-container-div');
//Auto-hide media container
this.mediaContainer.style.display = 'none';
//If the playlist wasn't set to open in the open map
if(!this.openMap.get(this.playlist.name)){
//Auto-hide media container
this.mediaContainer.style.display = 'none';
}
//Set dataset
this.mediaContainer.dataset['playlist'] = this.playlist.name;
for(let mediaIndex in this.playlist.media){
//Grab media object from playlist
@ -295,8 +298,23 @@ class playlistManager{
//Inject text content
mediaTitle.innerText = utils.unescapeEntities(media.title);
const deleteMediaIcon = document.createElement('i');
//set class
deleteMediaIcon.classList.add('queue-playlist-control', 'queue-playlist-media-delete-icon', 'danger-text', 'bi-trash-fill');
//Set title
deleteMediaIcon.title = 'Delete media from playlist';
//Set dataset
//It's probably more effecient to set this at mediaContainer level, but I don't want to crawl multiple parents later on
deleteMediaIcon.dataset['playlist'] = this.playlist.name;
deleteMediaIcon.dataset['uuid'] = media.uuid;
//Append items to media div
mediaDiv.appendChild(mediaTitle);
mediaDiv.appendChild(deleteMediaIcon);
//Handle input event listeners
deleteMediaIcon.addEventListener('click', this.deleteMedia.bind(this));
//Append media div to media container
this.mediaContainer.appendChild(mediaDiv);
@ -306,6 +324,31 @@ class playlistManager{
this.mediaContainer;
}
//I'd rather make this a class function but it's probably cleaner to not have to parent crawl
toggleMedia(event){
//Grab playlist title caret
const playlistTitleCaret = event.target.querySelector('i');
//I hope my mother doesn't see this next line, god I hate dot crawling...
const mediaContainer = event.target.parentNode.parentNode.nextElementSibling;
//If the div is hidden
if(mediaContainer.style.display == 'none'){
//Light up the button
event.target.classList.add('positive');
//Flip the caret
playlistTitleCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
//Show the div
mediaContainer.style.display = '';
}else{
//Unlight the button
event.target.classList.remove('positive');
//Flip the caret
playlistTitleCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
//Hide the div
mediaContainer.style.display = 'none';
}
}
addURL(event){
new addURLPopup(
event,
@ -331,16 +374,32 @@ class playlistManager{
event,
event.target.parentNode.dataset['playlist'],
this.client,
this.queuePanel.ownerDoc
this.queuePanel.ownerDoc,
handleOpenedMedia.bind(this)
);
function handleOpenedMedia(newName){
//do an ugly dot crawl to get the media container div
const mediaContainer = event.target.parentNode.parentNode.nextElementSibling;
//If the media container is visible
if(mediaContainer.style.display != 'none'){
//Set openMap to new name indicating the new playlist has it's media opened
this.openMap = newName;
}
}
}
queueAll(event){
client.socket.emit('queueChannelPlaylist', {playlist: event.target.parentNode.dataset['playlist']});
this.client.socket.emit('queueChannelPlaylist', {playlist: event.target.parentNode.dataset['playlist']});
}
deletePlaylist(event){
client.socket.emit('deleteChannelPlaylist', {playlist: event.target.parentNode.dataset['playlist']});
this.client.socket.emit('deleteChannelPlaylist', {playlist: event.target.parentNode.dataset['playlist']});
}
deleteMedia(event){
this.client.socket.emit('deleteChannelPlaylistMedia', {playlist: event.target.dataset['playlist'], uuid: event.target.dataset['uuid']});
}
}
@ -478,13 +537,15 @@ class defaultTitlesPopup{
}
class renamePopup{
constructor(event, playlist, client, doc){
constructor(event, playlist, client, doc, cb){
//Set Client
this.client = client;
//Set playlist
this.playlist = playlist
this.cb = cb;
//Create media popup and call async constructor when done
//unfortunately we cant call constructors asyncronously, and we cant call back to this from super, so we can't extend this as it stands :(
this.popup = new canopyUXUtils.popup('/renamePlaylist', true, this.asyncConstructor.bind(this), doc);
@ -513,6 +574,12 @@ class renamePopup{
name: this.renamePrompt.value
});
//if CB is a function
if(typeof this.cb == 'function'){
//Hand it back the new name
this.cb(this.renamePrompt.value);
}
//Close the popup
this.popup.closePopup();
}