Started client-side work on schedule searchin'
This commit is contained in:
parent
c081d9c4ff
commit
3ec770ba28
7 changed files with 196 additions and 24 deletions
|
|
@ -50,6 +50,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
<button id="queue-live-prompts-pushback-button" data-mode="pushback" title="Go Live, pushing-back any media scheduled during, or after the live steam." class="danger-button">Go Live (Pushback)</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="queue-search-prompts" style="display: none;">
|
||||
<div class="panel-control-prompt control-prompt">
|
||||
<%# Probably not the cleanest way to do this but fuggit %>
|
||||
<input placeholder="Search by media title or URL" id="queue-search-prompts-search-input" class="control-prompt">
|
||||
<button id="queue-search-prompts-search-button" class="positive-button bi-search"></button>
|
||||
</div>
|
||||
<div id="queue-search-prompts-result-div"></div>
|
||||
</div>
|
||||
<div id="queue-playlist-prompts" style="display: none;">
|
||||
<span class="queue-playlist-label-span interactive" id="queue-add-playlist-span">
|
||||
<i class="bi-plus" id="queue-add-playlist-icon"></i>
|
||||
|
|
|
|||
|
|
@ -144,6 +144,26 @@ div.dragging-queue-entry{
|
|||
margin: 0.15em 0.3em;
|
||||
}
|
||||
|
||||
/* Search Results */
|
||||
.queue-search-prompts-result-entry-div{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
text-wrap: nowrap;
|
||||
margin: 0 0.15em;
|
||||
padding: 0 0.15em;
|
||||
font-size: 0.8em
|
||||
}
|
||||
|
||||
.queue-search-prompts-result-entry-div p{
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.queue-search-prompts-result-entry-control-div i{
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
|
||||
/* playlist manager */
|
||||
.queue-playlist-label-span{
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -708,8 +708,9 @@ div.archived p{
|
|||
}
|
||||
|
||||
|
||||
.queue-playlist-media-container-div{
|
||||
.queue-playlist-media-container-div, #queue-search-prompts-result-div:not(:empty){
|
||||
background-color: var(--bg1-alt0);
|
||||
color: var(--accent1);
|
||||
border-block: var(--accent1) solid 1px;
|
||||
}
|
||||
|
||||
|
|
@ -726,7 +727,7 @@ div.archived p{
|
|||
color: var(--accent1);
|
||||
}
|
||||
|
||||
.queue-playlist-media-div.not-first{
|
||||
.queue-playlist-media-div.not-first, .queue-search-prompts-result-entry-div.not-first{
|
||||
border-top: var(--bg1) solid 1px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -907,8 +907,9 @@ div.archived p{
|
|||
}
|
||||
|
||||
|
||||
.queue-playlist-media-container-div{
|
||||
.queue-playlist-media-container-div, #queue-search-prompts-result-div:not(:empty){
|
||||
background-color: var(--bg1-alt0);
|
||||
color: var(--accent1);
|
||||
border-block: var(--accent1) solid 1px;
|
||||
}
|
||||
|
||||
|
|
@ -925,7 +926,7 @@ div.archived p{
|
|||
color: var(--accent1);
|
||||
}
|
||||
|
||||
.queue-playlist-media-div.not-first{
|
||||
.queue-playlist-media-div.not-first, .queue-search-prompts-result-entry-div.not-first{
|
||||
border-top: var(--bg1) solid 1px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,30 @@ class channel{
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* searches through local un-archived queue for matching titles/urls
|
||||
* @param {String} title - Title of media to search for
|
||||
* @param {String} url - URL of media to search fo4
|
||||
*/
|
||||
searchQueue(title, url){
|
||||
//Create array to hold results of the search
|
||||
const results = [];
|
||||
|
||||
//Run through the local queue
|
||||
for(const rawEntry of this.queue.entries()){
|
||||
//Quick syntatic sugar XP
|
||||
const entry = rawEntry[1];
|
||||
//If the entry title includes our title search string, or the URL is an exact match
|
||||
if(((title != null && entry.title.includes(title)) || (url != null && entry.url == url)) && entry.status != "archived"){
|
||||
//Plop that fucker down
|
||||
results.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
//Return all found entries
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and applies default config on any unset settings
|
||||
* @param {Boolean} force - Whether or not to forcefully reset already set settings
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ class queuePanel extends panelObj{
|
|||
//Get main control buttons
|
||||
this.addMediaButton = this.panelDocument.querySelector('#queue-add-media');
|
||||
this.goLiveButton = this.panelDocument.querySelector('#queue-go-live');
|
||||
this.searchButton = this.panelDocument.querySelector('#queue-search-media');
|
||||
this.scrollLockButton = this.panelDocument.querySelector('#queue-scroll-lock');
|
||||
this.queueDateButton = this.panelDocument.querySelector('#queue-date');
|
||||
this.playlistMenuButton = this.panelDocument.querySelector("#queue-playlists");
|
||||
|
|
@ -97,6 +98,7 @@ class queuePanel extends panelObj{
|
|||
//Get control divs
|
||||
this.addMediaDiv = this.panelDocument.querySelector('#queue-media-prompts');
|
||||
this.goLiveDiv = this.panelDocument.querySelector('#queue-live-prompts');
|
||||
this.searchDiv = this.panelDocument.querySelector('#queue-search-prompts');
|
||||
this.queueDateDiv = this.panelDocument.querySelector('#queue-control-date');
|
||||
this.playlistDiv = this.panelDocument.querySelector('#queue-playlist-prompts');
|
||||
|
||||
|
|
@ -110,6 +112,10 @@ class queuePanel extends panelObj{
|
|||
this.goLiveNamePrompt = this.panelDocument.querySelector("#queue-live-prompts-name-input");
|
||||
this.goLiveOverwriteButton = this.panelDocument.querySelector("#queue-live-prompts-overwrite-button");
|
||||
this.goLivePushbackButton = this.panelDocument.querySelector("#queue-live-prompts-pushback-button");
|
||||
//Search
|
||||
this.searchPrompt = this.panelDocument.querySelector('#queue-search-prompts-search-input');
|
||||
this.searchPromptButton = this.panelDocument.querySelector('#queue-search-prompts-search-button');
|
||||
this.searchResultDiv = this.panelDocument.querySelector('#queue-search-prompts-result-div')
|
||||
//Date Queue date
|
||||
this.queueDateDecrement = this.panelDocument.querySelector('#queue-control-date-decrement');
|
||||
this.queueDateIncrement = this.panelDocument.querySelector('#queue-control-date-increment');
|
||||
|
|
@ -163,6 +169,7 @@ class queuePanel extends panelObj{
|
|||
//control bar controls
|
||||
this.addMediaButton.addEventListener('click', this.toggleAddMedia.bind(this));
|
||||
this.goLiveButton.addEventListener('click', this.toggleGoLive.bind(this));
|
||||
this.searchButton.addEventListener('click', this.toggleSearch.bind(this));
|
||||
this.scrollLockButton.addEventListener('click', this.lockScroll.bind(this));
|
||||
this.queueDateButton.addEventListener('click', this.toggleDateControl.bind(this));
|
||||
this.playlistMenuButton.addEventListener('click', this.togglePlaylistDiv.bind(this));
|
||||
|
|
@ -274,6 +281,90 @@ class queuePanel extends panelObj{
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles add media UX
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
toggleSearch(event){
|
||||
//If the div is hidden
|
||||
if(this.searchDiv.style.display == 'none'){
|
||||
//Light up the button
|
||||
this.searchButton.classList.add('positive-button');
|
||||
//Show the div
|
||||
this.searchDiv.style.display = '';
|
||||
}else{
|
||||
//Unlight the button
|
||||
this.searchButton.classList.remove('positive-button');
|
||||
//Hide the div
|
||||
this.searchDiv.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
search(event){
|
||||
//Grab query
|
||||
const query = this.searchPrompt.value;
|
||||
|
||||
//If we're searching by URL
|
||||
if(utils.isURL(query)){
|
||||
//Render local items matching provided URL
|
||||
this.renderResults(client.searchQueue(undefined, query));
|
||||
}else{
|
||||
//Render local items matching title
|
||||
this.renderResults(client.searchQueue(query));
|
||||
}
|
||||
}
|
||||
|
||||
renderResults(results){
|
||||
//Keep track of whether or not we're on the first entry
|
||||
let notFirst = false;
|
||||
|
||||
for(const entry of results){
|
||||
//Create entry div
|
||||
const entryDiv = document.createElement('div');
|
||||
entryDiv.classList.add('queue-search-prompts-result-entry-div');
|
||||
|
||||
if(notFirst){
|
||||
entryDiv.classList.add('not-first');
|
||||
}
|
||||
|
||||
//Create and append entryTitle
|
||||
const entryTitle = document.createElement('p');
|
||||
entryTitle.textContent = utils.unescapeEntities(entry.title);
|
||||
|
||||
//Setup media tooltip
|
||||
entryTitle.addEventListener('mouseenter',(event)=>{
|
||||
//Display tooltip
|
||||
utils.ux.displayTooltip(event, this.renderMediaTooltip(entry), false, null, true, this.ownerDoc);
|
||||
});
|
||||
|
||||
//Append entry title
|
||||
entryDiv.appendChild(entryTitle);
|
||||
|
||||
//Create a div to hold result controls
|
||||
const controlDiv = document.createElement('div');
|
||||
controlDiv.classList.add('queue-search-prompts-result-entry-control-div');
|
||||
|
||||
//Create go to entry button
|
||||
const goToEntry = document.createElement('i');
|
||||
goToEntry.classList.add('bi-arrow-return-left')
|
||||
controlDiv.appendChild(goToEntry);
|
||||
|
||||
//Create queue entry button
|
||||
const queueEntry = document.createElement('i');
|
||||
queueEntry.classList.add('bi-play-circle')
|
||||
controlDiv.appendChild(queueEntry);
|
||||
|
||||
//Append control div to entry div
|
||||
entryDiv.appendChild(controlDiv);
|
||||
|
||||
//Add result to the result container
|
||||
this.searchResultDiv.appendChild(entryDiv);
|
||||
|
||||
//Throw not first flag for future entries
|
||||
notFirst = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles Go-Live UX
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
|
|
@ -766,26 +857,7 @@ class queuePanel extends panelObj{
|
|||
|
||||
//Tooltip generation
|
||||
//tooltip div
|
||||
const tooltipDiv = document.createElement('div');
|
||||
tooltipDiv.classList.add('media-tooltip');
|
||||
|
||||
//tooltip components
|
||||
//For each string
|
||||
for(let string of [
|
||||
`Title: ${entry[1].title}`,
|
||||
`File Name: ${entry[1].fileName}`,
|
||||
`Source: ${entry[1].type}`,
|
||||
`Duration: ${utils.ux.humieFriendlyDuration(entry[1].duration)}`,
|
||||
`Start Time: ${new Date(entry[1].startTime).toLocaleString()}${entry[1].startTimeStamp == 0 ? '' : ' (Started Late)'}`,
|
||||
`End Time: ${new Date(this.getMediaEnd(entry[1])).toLocaleString()}${entry[1].earlyEnd == null ? '' : ' (Ended Early)'}`
|
||||
]){
|
||||
//Create a 'p' node
|
||||
const component = document.createElement('p');
|
||||
//Fill it with the string
|
||||
component.textContent = utils.unescapeEntities(string);
|
||||
//Append it to the tooltip div
|
||||
tooltipDiv.append(component);
|
||||
}
|
||||
const tooltipDiv = this.renderMediaTooltip(entry[1]);
|
||||
|
||||
//Setup media tooltip
|
||||
entryDiv.addEventListener('mouseenter',(event)=>{
|
||||
|
|
@ -1042,6 +1114,38 @@ class queuePanel extends panelObj{
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Ingests a media object and returns a working tooltip ready to be placed into DOM
|
||||
* @param {Object} media - Media object to render tooltip for
|
||||
* @returns DOMNode containing tooltip div
|
||||
*/
|
||||
renderMediaTooltip(media){
|
||||
//Create tooltip div
|
||||
const tooltipDiv = document.createElement('div');
|
||||
tooltipDiv.classList.add('media-tooltip');
|
||||
|
||||
//tooltip components
|
||||
//For each string
|
||||
for(let string of [
|
||||
`Title: ${media.title}`,
|
||||
`File Name: ${media.fileName}`,
|
||||
`Source: ${media.type}`,
|
||||
`Duration: ${utils.ux.humieFriendlyDuration(media.duration)}`,
|
||||
`Start Time: ${new Date(media.startTime).toLocaleString()}${media.startTimeStamp == 0 ? '' : ' (Started Late)'}`,
|
||||
`End Time: ${new Date(this.getMediaEnd(media)).toLocaleString()}${media.earlyEnd == null ? '' : ' (Ended Early)'}`
|
||||
]){
|
||||
//Create a 'p' node
|
||||
const component = document.createElement('p');
|
||||
//Fill it with the string
|
||||
component.textContent = utils.unescapeEntities(string);
|
||||
//Append it to the tooltip div
|
||||
tooltipDiv.append(component);
|
||||
}
|
||||
|
||||
//Return tooltip
|
||||
return tooltipDiv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kills off hung tooltips
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
|
|
|
|||
|
|
@ -44,6 +44,20 @@ class canopyUtils{
|
|||
return min.getTime() < input.getTime() && max.getTime() > input.getTime();
|
||||
}
|
||||
|
||||
isURL(url){
|
||||
//attempt to makem a url
|
||||
try{
|
||||
new URL(url);
|
||||
//if it dont work
|
||||
}catch{
|
||||
//FUCK
|
||||
return false;
|
||||
}
|
||||
|
||||
//if it do, return true XP
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class canopyUXUtils{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue