Finished JSDoc for www/src/channel/*

This commit is contained in:
rainbow napkin 2025-09-05 08:37:16 -04:00
parent 2e89d4e6dc
commit 1aa836ba48
100 changed files with 10367 additions and 196 deletions

View file

@ -60,6 +60,9 @@ class playlistManager{
this.client.socket.on("userPlaylists", this.renderUserPlaylists.bind(this));
}
/**
* Handles Up-stream Document/Panel Changes from the parent Queue Panel object
*/
docSwitch(){
//Grab menus
this.channelPlaylistDiv = this.panelDocument.querySelector("#queue-channel-playlist-div");

View file

@ -13,26 +13,45 @@ 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 <https://www.gnu.org/licenses/>.*/
/**
* Class representing Queue Panel UX
*/
class queuePanel extends panelObj{
/**
* Instantiates a new Queue Panel object
* @param {channel} client - Parent Client Management Object
* @param {Document} panelDocument - Panel Document
*/
constructor(client, panelDocument){
//Call derived constructor
super(client, "Media Schedule", "/panel/queue", panelDocument);
//Current day
/**
* Current day, zero'd out to midnight
*/
this.day = new Date();
//Zero out day to midnight
this.day.setHours(0,0,0,0);
//Store releative scale of items in seconds, defaulting to 30 minute chunks
/**
* Schedule time scale in seconds, defaults to 30 minutes
*/
this.scale = 30 * 60;
//Create variable to hold rescale timer
/**
* Re-scale timer, counts down after re-sizing to clear re-size UI and show schedule again
*/
this.rescaleTimer = null;
//Autoscroll boolean
/**
* Enables auto-scroll on schedule UX
*/
this.autoscroll = true;
//Setup child classes
/**
* Child Playlist Manager Object
*/
this.playlistManager = new playlistManager(client, panelDocument, this);
//Define non-input event listeners
@ -112,7 +131,9 @@ class queuePanel extends panelObj{
this.killTimetips();
}
/**
* Handles Network-Related Event Listeners
*/
defineListeners(){
//Render queue when we receive a new copy of the queue data from the server
//Render queue should be called within an arrow function so that it's called with default parameters, and not handed an event as a date
@ -124,6 +145,9 @@ class queuePanel extends panelObj{
this.client.socket.on("error", this.handleQueueError.bind(this));
}
/**
* Handles Input-Related Event Listeners
*/
setupInput(){
//Re-render queue and time-marker on window resize as time-relative absolute positioning will be absolutely thrown
this.ownerDoc.defaultView.addEventListener('resize', this.resizeRender.bind(this));
@ -154,6 +178,10 @@ class queuePanel extends panelObj{
}
/* socket.io listeners */
/**
* Handles call from server to start media
* @param {Object} data - Data from server
*/
handleStart(data){
//If we're starting an HLS Livestream
if(data.media != null && data.media.type == 'livehls'){
@ -164,7 +192,10 @@ class queuePanel extends panelObj{
this.renderQueue();
}
handleEnd(data){
/**
* Handles call from server to end media
*/
handleEnd(){
//Reset Go Live button
this.goLiveButton.classList.replace('critical-danger-button', 'danger-button');
this.goLiveButton.classList.replace('bi-record', 'bi-record2');
@ -173,6 +204,9 @@ class queuePanel extends panelObj{
this.renderQueue();
}
/**
* Handles call from server to lock schedule
*/
handleScheduleLock(){
//Get queue lock button icon
const icon = this.queueLockButton.querySelector('i');
@ -186,6 +220,10 @@ class queuePanel extends panelObj{
}
}
/**
* Handles queue-related error from the server
* @param {Object} data - Data from server
*/
handleQueueError(data){
//Create a flag to reload the queue
let reloadQueue = false;
@ -207,6 +245,11 @@ class queuePanel extends panelObj{
}
/* queue control button functions */
/**
* Toggles add media UX
* @param {Event} event - Event passed down from Event Listener
*/
toggleAddMedia(event){
//If the div is hidden
if(this.addMediaDiv.style.display == 'none'){
@ -222,6 +265,10 @@ class queuePanel extends panelObj{
}
}
/**
* Toggles Go-Live UX
* @param {Event} event - Event passed down from Event Listener
*/
toggleGoLive(event){
//If we're not livestreaming
if(client.player.mediaHandler.type != "livehls"){
@ -244,11 +291,20 @@ class queuePanel extends panelObj{
}
/**
* Handles sending request to server to start a live stream
* @param {Event} event - Event passed down from Event Listener
*/
goLive(event){
//Start a livestream
client.socket.emit('goLive',{title: this.goLiveNamePrompt.value, mode: event.target.dataset['mode']});
}
/**
* Locks schedule scroll to current time marker
* @param {Event} event - Event passed down from Event Listener
* @param {Boolean} jumpToDay - whether or not to jump schedule to the current day
*/
lockScroll(event, jumpToDay = true){
//If we're supposed to jump to the current day
if(jumpToDay){
@ -271,6 +327,10 @@ class queuePanel extends panelObj{
}
}
/**
* Toggles schedule date control
* @param {Event} event - Event passed down from Event Listener
*/
toggleDateControl(event){
//If the div is hidden
if(this.queueDateDiv.style.display == 'none'){
@ -290,6 +350,10 @@ class queuePanel extends panelObj{
}
}
/**
* Toggles playlist management UX
* @param {Event} event - Event passed down from Event Listener
*/
togglePlaylistDiv(event){
//If the div is hidden
if(this.playlistDiv.style.display == 'none'){
@ -308,16 +372,28 @@ class queuePanel extends panelObj{
}
}
/**
* Sends request to server to clear media between a range of two dates
* @param {Event} event - Event passed down from Event Listener
*/
clearMedia(event){
//Call up the popup
new clearPopup(event, this.client, null, this.ownerDoc);
}
/**
* Sends request to lock the schedule
* @param {Event} event - Event passed down from Event Listener
*/
lockSchedule(event){
client.socket.emit('lock');
}
/* add queue controls */
/**
* Sends request to queue current URL after the last item
* @param {Event} event - Event passed down from Event Listener
*/
queueLast(event){
//Send off the request
this.client.socket.emit("queue",{url:this.addMediaLinkPrompt.value, title:this.addMediaNamePrompt.value});
@ -327,6 +403,10 @@ class queuePanel extends panelObj{
this.addMediaNamePrompt.value = '';
}
/**
* Sends request to queue current URL at the current time
* @param {Event} event - Event passed down from Event Listener
*/
queueAt(event){
//Call up the popup
new schedulePopup(event, this.client, this.addMediaLinkPrompt.value, this.addMediaNamePrompt.value, null, this.ownerDoc);
@ -337,6 +417,10 @@ class queuePanel extends panelObj{
}
/* set date controls */
/**
* Increments displayed schedule date
* @param {Event} event - Event passed down from Event Listener
*/
incrementDate(event){
//Increment day
this.day.setDate(this.day.getDate() + 1);
@ -344,6 +428,10 @@ class queuePanel extends panelObj{
this.setDay(this.day);
}
/**
* Decrements displayed schedule date
* @param {Event} event - Event passed down from Event Listener
*/
decrementDate(event){
//Decrement day
this.day.setDate(this.day.getDate() - 1);
@ -352,6 +440,10 @@ class queuePanel extends panelObj{
this.setDay(this.day);
}
/**
* Validates and sets display schedule date from user input
* @param {Event} event - Event passed down from Event Listener
*/
setQueueDate(event){
//If we have a valid date
if(this.queueDatePrompt.valueAsDate != null){
@ -361,6 +453,10 @@ class queuePanel extends panelObj{
}
}
/**
* Directly sets schedule display date
* @param {Date} date - Date to set schedule to
*/
setDay(date = new Date()){
//Set day
this.day = date;
@ -382,6 +478,10 @@ class queuePanel extends panelObj{
}
}
/**
* Handles time-scale changes on crtl+scroll
* @param {Event} event - Event passed down from Event Listener
*/
scaleScroll(event){
if(event.ctrlKey){
//I could sit here and work out why timetips break everything on scalescroll
@ -455,6 +555,9 @@ class queuePanel extends panelObj{
}
}
/**
* Un-locks scroll from curren time marker
*/
unlockScroll(){
//Disable scroll lock
this.autoscroll = false;
@ -462,12 +565,19 @@ class queuePanel extends panelObj{
this.scrollLockButton.classList.remove('positive-button');
}
/**
* Handles re-rendering schedule upon window re-size
* @param {Event} event - Event passed down from Event Listener
*/
resizeRender(event){
const date = new Date();
this.renderQueue(date);
this.renderTimeMarker(date);
}
/**
* Clears out queue container for re-render
*/
clearQueue(){
//If we have no body
if(this.ownerDoc.body == null){
@ -500,6 +610,10 @@ class queuePanel extends panelObj{
}
}
/**
*
* @param {Date} date - Current time,
*/
async fullRender(date = new Date()){
//Clear the queue
this.clearQueue();
@ -533,6 +647,10 @@ class queuePanel extends panelObj{
this.renderQueue(date);
}
/**
* Renders out schedule
* @param {Date} date - Date representing current time, defaults to new date object
*/
renderQueue(date = new Date()){
//Clear out queue container
this.queueContainer.innerHTML = '';
@ -880,6 +998,10 @@ class queuePanel extends panelObj{
}
/**
* Kills off hung tooltips
* @param {Event} event - Event passed down from Event Listener
*/
killTimetips(event){
//If we have an event and it's holding any mouse buttons
if(event != null && event.buttons != 0){
@ -894,6 +1016,10 @@ class queuePanel extends panelObj{
}
}
/**
* Render call called at 1-second intervals, handles time and livestream markers
* @param {Date} date - Date representing current time, defaults to new date object
*/
renderInterval(date = new Date()){
this.renderTimeMarker(date);
this.renderLiveStream(date, true);
@ -906,6 +1032,11 @@ class queuePanel extends panelObj{
this.renderIntervalTimer = setTimeout(this.renderInterval.bind(this), 1000);
}
/**
* Renders current time marker on to the schedule
* @param {Date} date - Date representing current time, defaults to new date object
* @param {Boolean} forceScroll - Whether or not to scroll the schedule on increment
*/
renderTimeMarker(date = new Date(), forceScroll = false){
//Calculate marker position by date
const markerPosition = Math.round(this.offsetByDate(date));
@ -960,6 +1091,10 @@ class queuePanel extends panelObj{
}
}
/**
* Renders queue scale markers
* @param {Date} inputDate - Date representing current time, defaults to new date object
*/
renderQueueScale(inputDate = new Date()){
//Clear out queue marker container
this.queueMarkerContainer.innerHTML = '';
@ -1023,6 +1158,11 @@ class queuePanel extends panelObj{
}
}
/**
* Renders live-stream marker
* @param {Date} inputDate - Date representing current time, defaults to new date object
* @param {Boolean} intervalRun - Whether or not this was run by renderInterval, defaults to false
*/
renderLiveStream(date = new Date(), intervalRun = false){
//Grab all live queue entries
const staleEntry = this.queueContainer.querySelector('.queue-entry.live');
@ -1188,6 +1328,12 @@ class queuePanel extends panelObj{
}
}
/**
* Calculate schedule offset from top or bottom of div from date
* @param {Date} date - Date to calculate from, defaults to now
* @param {Boolean} bottomOffset - Whether or not offset should be calculated from top or bottom
* @returns {Number} Offset from top/bottom of div in PX relative to time markers, calculated from given date
*/
offsetByDate(date = new Date(), bottomOffset = false){
//Pull start of day epoch from given date, make sure to use a new date object so we don't fuck up any date objects passed to us
const dayEpoch = new Date(date).setHours(0,0,0,0);
@ -1198,6 +1344,11 @@ class queuePanel extends panelObj{
return this.offsetByMilliseconds(curTime, bottomOffset);
}
/**
* Calculates date by offset pixels relative to schedule div top
* @param {Number} input - Pixels date is away from schedule div top
* @returns {Date} Date object representing date which was calculated from given pixel offset
*/
dateByOffset(input = 0){
//Get markers
const markers = this.panelDocument.querySelectorAll('span.queue-marker');
@ -1220,6 +1371,12 @@ class queuePanel extends panelObj{
return date;
}
/**
* Calculate schedule offset from top or bottom of div from JS Epoch (millis)
* @param {Number} input - JS Epoch (millis) to calculate from, defaults to 0
* @param {Boolean} bottomOffset - Whether or not offset should be calculated from top or bottom
* @returns {Number} Offset from top/bottom of div in PX relative to time markers, calculated from given date
*/
offsetByMilliseconds(input = 0, bottomOffset = false){
//Convert amount of milliseconds to a float, 0 representing the start of the day and 1 representing the end.
//Make sure to reverse it if bottomOffset is set to true
@ -1242,6 +1399,11 @@ class queuePanel extends panelObj{
return (offsetMax * timeFloat) + range[0];
}
/**
* Returns media end time
* @param {Object} media - media object to get end time from
* @returns {Number} Media end time as JS Epoch (millis)
*/
getMediaEnd(media){
//If we have an early end
if(media.earlyEnd != null){
@ -1253,22 +1415,51 @@ class queuePanel extends panelObj{
}
}
/**
* Class representing pop-up dialogue to schedule a piece of media
*/
class schedulePopup{
/**
* Instantiates a new schedule media Pop-up
* @param {Event} event - Event passed down from Event Listener
* @param {channel} client - Parent Client Management Object
* @param {String} url - URL/link to media to queue
* @param {String} title - Title of media to queue
* @param {Function} cb - Callback function, passed upon pop-up creation
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
*/
constructor(event, client, url, title, cb, doc){
//Set Client
/**
* Parent Client Management Object
*/
this.client = client;
//Set link
/**
* URL/Link to media to queue
*/
this.url = url;
//Set title
/**
* Title of media to queue
*/
this.title = title;
//Set callback
/**
* Callback function, passed upon pop-up creation
*/
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 :(
/**
* canopyUXUtils.popup() object
*/
this.popup = new canopyUXUtils.popup('/scheduleMedia', true, this.asyncConstructor.bind(this), doc);
}
/**
* Continuation of object construction, called after child popup object construction
*/
asyncConstructor(){
//Grab required UI elements
this.scheduleButton = this.popup.contentDiv.querySelector('#schedule-media-popup-schedule-button');
@ -1291,12 +1482,19 @@ class schedulePopup{
}
}
/**
* Defines input-related Event Handlers
*/
setupInput(){
//Setup input
this.scheduleButton.addEventListener('click', this.schedule.bind(this));
this.popup.popupDiv.addEventListener('keydown', this.schedule.bind(this));
}
/**
* Handles sending request to schedule item to the queue
* @param {Event} event - Event passed down from Event Listener
*/
schedule(event){
//If we clicked or hit enter
if(event.key == null || event.key == "Enter"){
@ -1312,12 +1510,26 @@ class schedulePopup{
}
}
/**
* Class representing pop-up dialogue for reschedule queue media
* @extends schedulePopup
*/
class reschedulePopup extends schedulePopup{
/**
* Instantiates a new schedule media Pop-up
* @param {Event} event - Event passed down from Event Listener
* @param {channel} client - Parent Client Management Object
* @param {Object} media - Media object to re-schedule
* @param {Function} cb - Callback function, passed upon pop-up creation
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
*/
constructor(event, client, media, cb, doc){
//Call derived constructor
super(event, client, null, null, cb, doc);
//Set media
/**
* Media Object to Re-Schedule
*/
this.media = media;
}
@ -1336,18 +1548,39 @@ class reschedulePopup extends schedulePopup{
}
}
/**
* Class represneting pop-up dialogue for clearing queue between a range of two dates
*/
class clearPopup{
/**
* Instantiates a new queue Clear Popup
* @param {Event} event - Event passed down from Event Listener
* @param {channel} client - Parent Client Management Object
* @param {Function} cb - Callback function, passed upon pop-up creation
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
*/
constructor(event, client, cb, doc){
//Set Client
/**
* Parent Client Management Object
*/
this.client = client;
//Set callback
/**
* Callback function, passed upon pop-up creation
*/
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 :(
/**
* canopyUXUtils.popup() object
*/
this.popup = new canopyUXUtils.popup('/clearMedia', true, this.asyncConstructor.bind(this), doc);
}
/**
* Continuation of object construction, called after child popup object construction
*/
asyncConstructor(){
//Grab required UI elements
this.clearButton = this.popup.contentDiv.querySelector('#clear-media-popup-clear-button');
@ -1375,12 +1608,19 @@ class clearPopup{
}
}
/**
* Defines input-related Event Handlers
*/
setupInput(){
//Setup input
this.clearButton.addEventListener('click', this.clear.bind(this));
this.popup.popupDiv.addEventListener('keydown', this.clear.bind(this));
}
/**
* Handles sending request to clear playlist between two dates to the server
* @param {Event} event - Event passed down from Event Listener
*/
clear(event){
//If we clicked or hit enter
if(event.key == null || event.key == "Enter"){