diff --git a/src/views/channel.ejs b/src/views/channel.ejs index f923223..8bdea7a 100644 --- a/src/views/channel.ejs +++ b/src/views/channel.ejs @@ -50,6 +50,7 @@ along with this program. If not, see . %> <%# panels %> + <%# main client %> diff --git a/src/views/partial/popup/addToPlaylist.ejs b/src/views/partial/popup/addToPlaylist.ejs new file mode 100644 index 0000000..8c875c3 --- /dev/null +++ b/src/views/partial/popup/addToPlaylist.ejs @@ -0,0 +1,21 @@ +<%# Canopy - The next generation of stoner streaming software +Copyright (C) 2024-2025 Rainbownapkin and the TTN Community + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . %> +<%# %> + +
+ + +
\ No newline at end of file diff --git a/www/css/panel/queue.css b/www/css/panel/queue.css index a88f22e..37c861d 100644 --- a/www/css/panel/queue.css +++ b/www/css/panel/queue.css @@ -224,6 +224,26 @@ div.dragging-queue-entry{ resize: vertical; } +.queue-playlist-media-div{ + margin: 0 0.15em; + padding: 0 0.15em; +} + + + +.queue-playlist-add-url-button i.bi-link-45deg{ + margin-right: 0.5em; +} + +.queue-playlist-add-url-button i{ + display: inline-block; + margin: 0; + padding: 0; + width: 0.5em; +} + + + /* date */ #queue-control-date{ display: flex; diff --git a/www/css/theme/movie-night.css b/www/css/theme/movie-night.css index a7534ad..07c61cf 100644 --- a/www/css/theme/movie-night.css +++ b/www/css/theme/movie-night.css @@ -560,11 +560,20 @@ div.archived p{ color: var(--accent1-alt0); } -.queue-playlist-control:not(.danger-button):not(:hover){ +.queue-playlist-control:not(.danger-button):not(:hover).queue-playlist-control:not(.positive-button):not(:hover){ background-color: var(--bg1-alt0); color: var(--accent1); } + +.queue-playlist-media-div.not-first{ + border-top: var(--bg1) solid 1px; +} + +.queue-playlist-control:not(.queue-playlist-queue-random-button){ + border-left: var(--accent1-alt0) solid 1px; +} + /* altcha theming*/ div.altcha{ box-shadow: 4px 4px 1px var(--bg1-alt0) inset; diff --git a/www/js/channel/panels/queuePanel.js b/www/js/channel/panels/queuePanel.js index 9d436ce..24a1854 100644 --- a/www/js/channel/panels/queuePanel.js +++ b/www/js/channel/panels/queuePanel.js @@ -1,3 +1,18 @@ +/*Canopy - The next generation of stoner streaming software +Copyright (C) 2024-2025 Rainbownapkin and the TTN Community + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see .*/ class queuePanel extends panelObj{ constructor(client, panelDocument){ //Call derived constructor @@ -1031,296 +1046,6 @@ class queuePanel extends panelObj{ } } -class playlistManager{ - constructor(client, panelDocument, queuePanel){ - //Set client - this.client = client; - //Set panel document - this.panelDocument = panelDocument; - //Set parent queue panel - this.queuePanel = queuePanel; - - //Define Listeners - this.defineListeners(); - } - - defineListeners(){ - this.client.socket.on("chanPlaylists", this.renderChannelPlaylists.bind(this)); - } - - docSwitch(){ - //Grab menus - this.channelPlaylistDiv = this.panelDocument.querySelector("#queue-channel-playlist-div"); - - //Grab controls - this.createPlaylistSpan = this.panelDocument.querySelector('#queue-add-playlist-span'); - this.channelPlaylistLabel = this.panelDocument.querySelector('#queue-channel-playlist-span'); - this.channelPlaylistCaret = this.panelDocument.querySelector('#queue-channel-playlist-toggle'); - - //Setup Input - this.setupInput(); - } - - setupInput(){ - this.createPlaylistSpan.addEventListener('click', (event)=>{new newPlaylistPopup(event, this.client, this.queuePanel.ownerDoc)}) - this.channelPlaylistLabel.addEventListener('click', this.toggleChannelPlaylists.bind(this)); - } - - /* queue control button functions */ - toggleChannelPlaylists(event){ - //If the div is hidden - if(this.channelPlaylistDiv.style.display == 'none'){ - //Light up the button - this.channelPlaylistLabel.classList.add('positive'); - //Flip the caret - this.channelPlaylistCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill'); - //Show the div - this.channelPlaylistDiv.style.display = ''; - }else{ - //Unlight the button - this.channelPlaylistLabel.classList.remove('positive'); - //Flip the caret - this.channelPlaylistCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill'); - //Hide the div - this.channelPlaylistDiv.style.display = 'none'; - } - } - - renderChannelPlaylists(data){ - //Clear channel playlist div - this.channelPlaylistDiv.innerHTML = ''; - - //For every playlist sent down from the server - for(let playlistIndex in data){ - //Get playlist from data - const playlist = data[playlistIndex]; - - //Create a new playlist div - const playlistDiv = document.createElement('div'); - //Set it's class - playlistDiv.classList.add('queue-playlist-div'); - - //Set playlist div dataset - playlistDiv.dataset.name = playlist.name; - - //Create span to hold playlist entry line contents - const playlistSpan = document.createElement('span'); - //Set classes - playlistSpan.classList.add('queue-playlist-span'); - - //If this isn't our first rodeo - if(playlistIndex != 0){ - //make note - playlistSpan.classList.add('not-first'); - } - - //pre-render and keep this so we can use it later - const mediaContainer = renderMedia(); - - //Append items to playlist entry line - playlistSpan.appendChild(renderLabels()); - playlistSpan.appendChild(renderControls()); - - //Append items to playlist div - playlistDiv.appendChild(playlistSpan); - playlistDiv.appendChild(mediaContainer); - - //Append current playlist div to the channel playlists div - this.channelPlaylistDiv.appendChild(playlistDiv); - - //aux rendering functions - function renderLabels(){ - //Create playlist label span - const playlistLabels = document.createElement('span'); - //Set it's class - playlistLabels.classList.add('queue-playlist-labels-span'); - - //create playlist title span - const playlistTitleSpan = document.createElement('span'); - //Set class - playlistTitleSpan.classList.add('queue-playlist-title-span', 'interactive'); - - //Create playlist title caret - const playlistTitleCaret = document.createElement('i'); - //Set class - playlistTitleCaret.classList.add('bi-caret-right-fill'); - - //Create playlist title label - const playlistTitle = document.createElement('p'); - //Set it's class - playlistTitle.classList.add('queue-playlist-title'); - //Unescape Sanatized Enteties and safely inject as plaintext - playlistTitle.innerText = utils.unescapeEntities(playlist.name); - - //Construct playlist title span - playlistTitleSpan.appendChild(playlistTitleCaret); - playlistTitleSpan.appendChild(playlistTitle); - - //Create playlist count label - const playlistCount = document.createElement('p'); - //Set it's class - playlistCount.classList.add('queue-playlist-count'); - //List video count - playlistCount.innerText = `Count: ${playlist.media.length}`; - - //Append items to playlist labels span - playlistLabels.appendChild(playlistTitleSpan); - playlistLabels.appendChild(playlistCount); - - //Define input listeners - playlistTitleSpan.addEventListener('click', toggleMedia.bind(this)); - - //return playlistLabels - return playlistLabels; - - function toggleMedia(){ - //If the div is hidden - if(mediaContainer.style.display == 'none'){ - //Light up the button - playlistTitleSpan.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 - playlistTitleSpan.classList.remove('positive'); - //Flip the caret - playlistTitleCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill'); - //Hide the div - mediaContainer.style.display = 'none'; - } - } - } - - function renderControls(){ - //Create playlist control span - const playlistControls = document.createElement('span'); - //Set it's class - playlistControls.classList.add('queue-playlist-control-span'); - - //Create queue all button - const playlistQueueRandomButton = document.createElement('button'); - //Set it's classes - playlistQueueRandomButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control'); - //Inject text content - playlistQueueRandomButton.textContent = 'Queue Random'; - - //Create queue all button - const playlistQueueAllButton = document.createElement('button'); - //Set it's classes - playlistQueueAllButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control'); - //Inject text content - playlistQueueAllButton.textContent = 'Queue All'; - - //Create delete button - const playlistDeleteButton = document.createElement('button'); - //Set it's classes - playlistDeleteButton.classList.add('queue-playlist-delete-button', 'queue-playlist-control', 'danger-button', 'bi-trash-fill'); - - //Append items to playlist control span - playlistControls.appendChild(playlistQueueRandomButton); - playlistControls.appendChild(playlistQueueAllButton); - playlistControls.appendChild(playlistDeleteButton); - - //Define input event listeners - playlistQueueAllButton.addEventListener('click', queueAll); - playlistDeleteButton.addEventListener('click', deletePlaylist); - - return playlistControls; - } - - function renderMedia(){ - //Create media container div - const mediaContainer = document.createElement('div'); - //Set classes - mediaContainer.classList.add('queue-playlist-media-container-div'); - //Auto-hide media container - mediaContainer.style.display = 'none'; - - for(let media of playlist.media){ - //Create media div - const mediaDiv = document.createElement('div'); - //Set class - mediaDiv.classList.add('queue-playlist-media-div'); - - //Create media title - const mediaTitle = document.createElement('p'); - //Set class - mediaTitle.classList.add('queue-playlist-media-title'); - //Inject text content - mediaTitle.innerText = utils.unescapeEntities(media.title); - - //Append items to media div - mediaDiv.appendChild(mediaTitle); - - //Append media div to media container - mediaContainer.appendChild(mediaDiv); - } - - //return media container - return mediaContainer; - } - - //playlist control functions - function queueAll(){ - client.socket.emit('queueChannelPlaylist', {playlist: playlist.name}); - } - - function deletePlaylist(){ - client.socket.emit('deleteChannelPlaylist', {playlist: playlist.name}); - } - } - } - -} - -class newPlaylistPopup{ - constructor(event, client, doc){ - //Set Client - this.client = client; - - //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('/newPlaylist', true, this.asyncConstructor.bind(this), doc); - } - - asyncConstructor(){ - this.name = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-name'); - this.defaultTitles = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-default-titles'); - this.location = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-location'); - this.saveButton = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-save'); - - this.setupInput(); - } - - setupInput(){ - //Setup input - this.saveButton.addEventListener('click', this.createPlaylist.bind(this)); - this.popup.popupDiv.addEventListener('keydown', this.createPlaylist.bind(this)); - } - - createPlaylist(event){ - //If we clicked or hit enter - if(event.key == null || event.key == "Enter"){ - - //If we're saving to the channel - if(this.location.value == 'channel'){ - //Tell the server to create a new channel playlist - this.client.socket.emit('createChannelPlaylist', { - playlist: this.name.value, - defaultTitles: this.defaultTitles.value.split('\n') - }) - } - - //Close the popup - this.popup.closePopup(); - } - } - - -} - class schedulePopup{ constructor(event, client, url, title, cb, doc){ //Set Client diff --git a/www/js/channel/panels/queuePanel/playlistManager.js b/www/js/channel/panels/queuePanel/playlistManager.js new file mode 100644 index 0000000..32b5af4 --- /dev/null +++ b/www/js/channel/panels/queuePanel/playlistManager.js @@ -0,0 +1,441 @@ +/*Canopy - The next generation of stoner streaming software +Copyright (C) 2024-2025 Rainbownapkin and the TTN Community + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see .*/ +class playlistManager{ + constructor(client, panelDocument, queuePanel){ + //Set client + this.client = client; + //Set panel document + this.panelDocument = panelDocument; + //Set parent queue panel + this.queuePanel = queuePanel; + + //Define Listeners + this.defineListeners(); + } + + defineListeners(){ + this.client.socket.on("chanPlaylists", this.renderChannelPlaylists.bind(this)); + } + + docSwitch(){ + //Grab menus + this.channelPlaylistDiv = this.panelDocument.querySelector("#queue-channel-playlist-div"); + + //Grab controls + this.createPlaylistSpan = this.panelDocument.querySelector('#queue-add-playlist-span'); + this.channelPlaylistLabel = this.panelDocument.querySelector('#queue-channel-playlist-span'); + this.channelPlaylistCaret = this.panelDocument.querySelector('#queue-channel-playlist-toggle'); + + //Setup Input + this.setupInput(); + } + + setupInput(){ + this.createPlaylistSpan.addEventListener('click', (event)=>{new newPlaylistPopup(event, this.client, this.queuePanel.ownerDoc)}) + this.channelPlaylistLabel.addEventListener('click', this.toggleChannelPlaylists.bind(this)); + } + + /* queue control button functions */ + toggleChannelPlaylists(event){ + //If the div is hidden + if(this.channelPlaylistDiv.style.display == 'none'){ + //Light up the button + this.channelPlaylistLabel.classList.add('positive'); + //Flip the caret + this.channelPlaylistCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill'); + //Show the div + this.channelPlaylistDiv.style.display = ''; + }else{ + //Unlight the button + this.channelPlaylistLabel.classList.remove('positive'); + //Flip the caret + this.channelPlaylistCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill'); + //Hide the div + this.channelPlaylistDiv.style.display = 'none'; + } + } + + //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... + renderChannelPlaylists(data){ + //Clear channel playlist div + this.channelPlaylistDiv.innerHTML = ''; + + //For every playlist sent down from the server + for(let playlistIndex in data){ + //Get playlist from data + const playlist = data[playlistIndex]; + + //Create a new playlist div + const playlistDiv = document.createElement('div'); + //Set it's class + playlistDiv.classList.add('queue-playlist-div'); + + //Set playlist div dataset + playlistDiv.dataset.name = playlist.name; + + //Create span to hold playlist entry line contents + const playlistSpan = document.createElement('span'); + //Set classes + playlistSpan.classList.add('queue-playlist-span'); + + //If this isn't our first rodeo + if(playlistIndex != 0){ + //make note + playlistSpan.classList.add('not-first'); + } + + //pre-render and keep this so we can use it later + const mediaContainer = renderMedia(); + + //Append items to playlist entry line + playlistSpan.appendChild((renderLabels.bind(this))()); + playlistSpan.appendChild((renderControls.bind(this))()); + + //Append items to playlist div + playlistDiv.appendChild(playlistSpan); + playlistDiv.appendChild(mediaContainer); + + //Append current playlist div to the channel playlists div + this.channelPlaylistDiv.appendChild(playlistDiv); + + //aux rendering functions + function renderLabels(){ + //Create playlist label span + const playlistLabels = document.createElement('span'); + //Set it's class + playlistLabels.classList.add('queue-playlist-labels-span'); + + //create playlist title span + const playlistTitleSpan = document.createElement('span'); + //Set class + playlistTitleSpan.classList.add('queue-playlist-title-span', 'interactive'); + + //Create playlist title caret + const playlistTitleCaret = document.createElement('i'); + //Set class + playlistTitleCaret.classList.add('bi-caret-right-fill'); + + //Create playlist title label + const playlistTitle = document.createElement('p'); + //Set it's class + playlistTitle.classList.add('queue-playlist-title'); + //Unescape Sanatized Enteties and safely inject as plaintext + playlistTitle.innerText = utils.unescapeEntities(playlist.name); + + //Construct playlist title span + playlistTitleSpan.appendChild(playlistTitleCaret); + playlistTitleSpan.appendChild(playlistTitle); + + //Create playlist count label + const playlistCount = document.createElement('p'); + //Set it's class + playlistCount.classList.add('queue-playlist-count'); + //List video count + playlistCount.innerText = `Count: ${playlist.media.length}`; + + //Append items to playlist labels span + playlistLabels.appendChild(playlistTitleSpan); + playlistLabels.appendChild(playlistCount); + + //Define input listeners + playlistTitleSpan.addEventListener('click', toggleMedia.bind(this)); + + //return playlistLabels + return playlistLabels; + + function toggleMedia(){ + //If the div is hidden + if(mediaContainer.style.display == 'none'){ + //Light up the button + playlistTitleSpan.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 + playlistTitleSpan.classList.remove('positive'); + //Flip the caret + playlistTitleCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill'); + //Hide the div + mediaContainer.style.display = 'none'; + } + } + } + + function renderControls(){ + //Create playlist control span + const playlistControls = document.createElement('span'); + //Set it's class + playlistControls.classList.add('queue-playlist-control-span'); + + //Create queue all button + const playlistQueueRandomButton = document.createElement('button'); + //Set it's classes + playlistQueueRandomButton.classList.add('queue-playlist-queue-random-button', 'queue-playlist-control'); + //Inject text content + playlistQueueRandomButton.textContent = 'Random'; + //Set title + playlistQueueRandomButton.title = 'Queue Random Item from Playlist'; + + //Create queue all button + const playlistQueueAllButton = document.createElement('button'); + //Set it's classes + playlistQueueAllButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control'); + //Inject text content + playlistQueueAllButton.textContent = 'All'; + //Set title + playlistQueueAllButton.title = 'Queue Entire Playlist'; + + //Create add from URL button + const playlistAddURLButton = document.createElement('button'); + //Set it's classes + playlistAddURLButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'positive-button'); + //Set Tile + playlistAddURLButton.title = 'Add To Playlist From URL' + + //Create playlist icons (we're using two so we're putting them inside the button :P) + const playlistAddIcon = document.createElement('i'); + const playlistLinkIcon = document.createElement('i'); + //set classes + playlistAddIcon.classList.add('bi-plus-lg'); + playlistLinkIcon.classList.add('bi-link-45deg'); + + playlistAddURLButton.appendChild(playlistAddIcon); + playlistAddURLButton.appendChild(playlistLinkIcon); + + //Create default titles button + const playlistDefaultTitlesButton = document.createElement('button'); + //Set classes + playlistDefaultTitlesButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-tags-fill', 'positive-button'); + //Set title + playlistDefaultTitlesButton.title = 'Change Default Titles' + + //Create rename button + const playlistRenameButton = document.createElement('button'); + //Set it's classes + playlistRenameButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-input-cursor-text', 'positive-button'); + //Set title + playlistRenameButton.title = 'Rename Playlist' + + + //Create delete button + const playlistDeleteButton = document.createElement('button'); + //Set it's classes + playlistDeleteButton.classList.add('queue-playlist-delete-button', 'queue-playlist-control', 'danger-button', 'bi-trash-fill'); + //Set title + playlistDeleteButton.title = 'Delete Playlist' + + //Append items to playlist control span + playlistControls.appendChild(playlistQueueRandomButton); + playlistControls.appendChild(playlistQueueAllButton); + playlistControls.appendChild(playlistAddURLButton); + playlistControls.appendChild(playlistDefaultTitlesButton); + playlistControls.appendChild(playlistRenameButton); + playlistControls.appendChild(playlistDeleteButton); + + //Define input event listeners + playlistAddURLButton.addEventListener('click', (event)=>{new addURLPopup(event, playlist.name, this.client, this.queuePanel.ownerDoc)}) + playlistQueueAllButton.addEventListener('click', queueAll); + playlistDeleteButton.addEventListener('click', deletePlaylist); + + return playlistControls; + } + + function renderMedia(){ + //Create media container div + const mediaContainer = document.createElement('div'); + //Set classes + mediaContainer.classList.add('queue-playlist-media-container-div'); + //Auto-hide media container + mediaContainer.style.display = 'none'; + + for(let mediaIndex in playlist.media){ + //Grab media object from playlist + const media = playlist.media[mediaIndex]; + + //Create media div + const mediaDiv = document.createElement('div'); + //Set class + mediaDiv.classList.add('queue-playlist-media-div'); + + //If this isn't our first rodeo + if(mediaIndex != 0){ + mediaDiv.classList.add('not-first'); + } + + //Create media title + const mediaTitle = document.createElement('p'); + //Set class + mediaTitle.classList.add('queue-playlist-media-title'); + //Inject text content + mediaTitle.innerText = utils.unescapeEntities(media.title); + + //Append items to media div + mediaDiv.appendChild(mediaTitle); + + //Append media div to media container + mediaContainer.appendChild(mediaDiv); + } + + //return media container + return mediaContainer; + } + + //playlist control functions + function queueAll(){ + client.socket.emit('queueChannelPlaylist', {playlist: playlist.name}); + } + + function deletePlaylist(){ + client.socket.emit('deleteChannelPlaylist', {playlist: playlist.name}); + } + } + } + +} + +class newPlaylistPopup{ + constructor(event, client, doc){ + //Set Client + this.client = client; + + //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('/newPlaylist', true, this.asyncConstructor.bind(this), doc); + } + + asyncConstructor(){ + this.name = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-name'); + this.defaultTitles = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-default-titles'); + this.location = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-location'); + this.saveButton = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-save'); + + this.setupInput(); + } + + setupInput(){ + //Setup input + this.saveButton.addEventListener('click', this.createPlaylist.bind(this)); + this.popup.popupDiv.addEventListener('keydown', this.createPlaylist.bind(this)); + } + + createPlaylist(event){ + //If we clicked or hit enter + if(event.key == null || event.key == "Enter"){ + + //If we're saving to the channel + if(this.location.value == 'channel'){ + //Tell the server to create a new channel playlist + this.client.socket.emit('createChannelPlaylist', { + playlist: this.name.value, + defaultTitles: this.defaultTitles.value.split('\n') + }) + } + + //Close the popup + this.popup.closePopup(); + } + } +} + +class addURLPopup{ + constructor(event, playlist, client, doc){ + //Set Client + this.client = client; + + //Set playlist + this.playlist = playlist + + //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('/addToPlaylist', true, this.asyncConstructor.bind(this), doc); + } + + asyncConstructor(){ + this.urlPrompt = this.popup.contentDiv.querySelector('#playlist-add-media-popup-prompt'); + this.addButton = this.popup.contentDiv.querySelector('#playlist-add-media-popup-button'); + + this.setupInput(); + } + + setupInput(){ + //Setup input + this.addButton.addEventListener('click', this.addToPlaylist.bind(this)); + this.popup.popupDiv.addEventListener('keydown', this.addToPlaylist.bind(this)); + } + + addToPlaylist(event){ + //If we clicked or hit enter + if(event.key == null || event.key == "Enter"){ + + //Tell the server to create a new channel playlist + this.client.socket.emit('addToChannelPlaylist', { + playlist: this.playlist, + url: this.urlPrompt.value + }); + + //Close the popup + this.popup.closePopup(); + } + } +} + +class defaultTitlesPopup{ + constructor(event, playlist, titles, client, doc){ + //Set Client + this.client = client; + + //Set playlist + this.playlist = playlist + + //Set title string + this.titles = titles.join('\n'); + + //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('/addToPlaylist', true, this.asyncConstructor.bind(this), doc); + } + + asyncConstructor(){ + this.urlPrompt = this.popup.contentDiv.querySelector('#playlist-add-media-popup-prompt'); + this.addButton = this.popup.contentDiv.querySelector('#playlist-add-media-popup-button'); + + this.setupInput(); + } + + setupInput(){ + //Setup input + this.addButton.addEventListener('click', this.addToPlaylist.bind(this)); + this.popup.popupDiv.addEventListener('keydown', this.addToPlaylist.bind(this)); + } + + addToPlaylist(event){ + //If we clicked or hit enter + if(event.key == null || event.key == "Enter"){ + + //Tell the server to create a new channel playlist + this.client.socket.emit('addToChannelPlaylist', { + playlist: this.playlist, + url: this.urlPrompt.value + }); + + //Close the popup + this.popup.closePopup(); + } + } +} diff --git a/www/js/utils.js b/www/js/utils.js index 63c1ac0..3b70a2d 100644 --- a/www/js/utils.js +++ b/www/js/utils.js @@ -360,6 +360,7 @@ class canopyUXUtils{ this.content = content; this.ajaxPopup = ajaxPopup; this.cb = cb; + console.log(doc); this.doc = doc; //define popup nodes this.createPopup();