<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Thrimbletrimmer Goes Forth</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <!-- <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> --> <style> html, body { height:100%; margin:0px; background-color:darkgrey; } .sectionContainer { margin:24px auto; padding:32px; border-radius:4px; background:white; box-shadow:0 0 34px rgba(0,0,0,.26); max-width:1280px; } #QueueTable { width:100%; border-collapse: collapse; text-align: center; } #QueueTable, #QueueTable th, #QueueTable td { border: 1px solid #cccccc; } #QueueTable tr:nth-child(even) { background-color: #f2f2f2; } #QueueTable tr:hover { background-color:#dddddd; } #QueueTable th { line-height:32px; } .filterMenu { display: inline-block; padding: 10px; background-color: rgb(221, 221, 221); border-radius: 5px 5px 0px 0px; } .filterList { display:none; List-style-type:none; margin:10px 0px 0px -10px; padding:10px; border:1px solid black; position:absolute; background-color:white; min-width:100px; } .filterMenu:hover .filterList { display:inline-block; } </style> <style> /* Styles based on event category */ #QueueTable .RDP { background-color: #f4cccc; } </style> </head> <body> <div> <!-- <div class="sectionContainer" style="display:none;"> <table> <tr> <th>Stream</th> <th>Start Time</th> <th>End Time</th> <th></th> </tr> <tr> <td><input id="StreamName" value="gamesdonequick" /></td> <td><input id="StreamStart" value="2019-01-06T16:00:00" /></td> <td><input id="StreamEnd" value="2019-01-06T17:00:00" /></td> <td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td> </tr> <tr> <td><a href="javascript:alert('seabats, lunarjade, gamesdonequick');">Streams</a></td> <td><a href="javascript:window.open('/files/' + document.getElementById('StreamName').value + '/source', '_blank');">Hours</a></td> <td></td> <td></td> <td></td> <td></td> </tr> </table> </div> --> <div class="sectionContainer"> <h1 style="color:#1976d2;font-size:34px;line-height:38px;">Wubloader Queue</h1> <!-- Add in filters based on time period, category, and state --> <!-- Throw in JQueryUI to run the filter menus, not worth re-inventing the wheel --> <style> .ui-menu { width: 150px; } </style> <div id="FiltersMenu"> <div class="filterMenu" style="padding-bottom:7px;"> <input id="DateFilterStart" placeholder="Start Date" /> </div> <div class="filterMenu" style="padding-bottom:7px;"> <input id="DateFilterEnd" placeholder="End Date" /> </div> <div id="CategoryFiltersMenu" class="filterMenu"> <div>Category Filter</div> <ul id="CategoryFilter" class="filterList"></ul> </div> <div id="StateFiltersMenu" class="filterMenu"> <div>State Filter</div> <ul id="StateFilter" class="filterList"></ul> </div> <input type="button" value="Apply Filters" onclick="applyFilters()"/> <input type="button" value="Reset Filters" onclick="window.location.href = '/thrimbletrimmer/dashboard.html'"/> </div> <table id="QueueTable"> <tr> <th>Start Time</th> <th>End Time</th> <th>Category</th> <th>Description</th> <th>State</th> <th>Edit</th> <th>Link</th> <th>Edit Time</th> <th>Upload Time</th> </tr> </table> </div> </div> <script> // var startOfHour = new Date(new Date().setMinutes(0,0,0)); // document.getElementById("StreamStart").value = new Date(startOfHour.getTime() - 1000*60*60).toISOString().substring(0,19); // document.getElementById("StreamEnd").value = startOfHour.toISOString().substring(0,19); function sanitizeInput(input) { let tempElement = document.createElement("SPAN"); tempElement.appendChild(document.createTextNode(input)); return tempElement.innerHTML; } async function getEvents() { let response = await fetch("/thrimshim"); let data = await response.json(); //Sanitize user inputs that could be used for xss data.forEach(event => { event.category = sanitizeInput(event.category); event.description = sanitizeInput(event.description); }) return data; } function populateFilters(events) { var urlParams = new URLSearchParams(window.location.search); //Set up Date filters if (urlParams.has("start")) { document.getElementById("DateFilterStart").value = urlParams.get("start"); } if (urlParams.has("end")) { document.getElementById("DateFilterEnd").value = urlParams.get("end"); } //Set up Category filters let categoryFilters = urlParams.has("category") ? urlParams.get("category").split(","):null; new Set(events.map(event => event.category).sort()).forEach((category, index) => { let row = document.createElement("TR"); row.innerHTML = `<li><input type="checkbox" name="categoryCheckbox-${index}" filtervalue="${category}" ${!categoryFilters || categoryFilters.indexOf(category) >=0 ? "checked":""}><label for="categoryCheckbox-${index}">${category}</label></li>`; document.getElementById('CategoryFilter').appendChild(row); }); //Set up State filters let stateFilters = urlParams.has("state") ? urlParams.get("state").split(","):null; //new Set(events.map(event => event.state).sort()).forEach((state, index) => { ["UNEDITED", "EDITED", "CLAIMED", "FINALIZING", "TRANSCODING", "DONE"].forEach((state, index) => { let row = document.createElement("TR"); row.innerHTML = `<li><input type="checkbox" name="stateCheckbox-${index}" filtervalue="${state}" ${!stateFilters || stateFilters.indexOf(state) >=0 ? "checked":""}><label for="stateCheckbox-${index}">${state}</label></li>`; document.getElementById('StateFilter').appendChild(row); }); return events; } function filterEvents(events) { if(!window.location.search) { return events; } var urlParams = new URLSearchParams(window.location.search); if(urlParams.has("start")) { let startDate = new Date(urlParams.get("start")); events = events.filter(event => new Date(event.event_start) >= startDate); } if(urlParams.has("end")) { let endDate = new Date(urlParams.get("end")); events = events.filter(event => new Date(event.event_start) <= endDate); } if(urlParams.has("category")) { events = events.filter(event => urlParams.get("category").split(",").indexOf(event.category) >= 0); } if(urlParams.has("state")) { events = events.filter(event => urlParams.get("state").split(",").indexOf(event.state) >= 0); } return events; } function populateTable (events) { events.forEach(event => { if(!event.description) { //If a row doesn't have a description, it's probably orphaned from the spreadsheet, and does not need to be displayed. return; } let row = document.createElement("TR"); row.innerHTML = ` <td>${event.event_start}</td> <td>${event.event_end}</td> <td class="${event.category.replace(/ /g, "")}">${event.category}</td> <td>${event.description}</td> <td>${event.state}</td> <td><a href="/thrimbletrimmer?id=${event.id}">Edit</a></td> <td>${event.video_link ? "<a href='"+event.video_link+"'>Link</a>":""}</td> <td>${event.edit_time ? event.edit_time.substring(0,19):""}</td> <td>${event.upload_time ? event.upload_time.substring(0,19):""}</td> `; document.getElementById('QueueTable').appendChild(row); }); } function applyFilters() { let startDateFilter = document.getElementById("DateFilterStart").value; let endDateFilter = document.getElementById("DateFilterEnd").value; let categoryfilters = Array.from(document.querySelectorAll("#CategoryFilter :checked")).map(checkbox => checkbox.getAttribute("filtervalue")).join(); let statefilters = Array.from(document.querySelectorAll("#StateFilter :checked")).map(checkbox => checkbox.getAttribute("filtervalue")).join(); window.location.href = `/thrimbletrimmer/dashboard.html?${startDateFilter ? "start="+startDateFilter+"&":""}${endDateFilter ? "end="+endDateFilter+"&":""}category=${categoryfilters}&state=${statefilters}`; } //On Page Load getEvents().then(populateFilters).then(filterEvents).then(populateTable); </script> </body> </html>