diff --git a/www/css/channelGuide.css b/www/css/channelGuide.css
index 531e4b5..f30075c 100644
--- a/www/css/channelGuide.css
+++ b/www/css/channelGuide.css
@@ -47,7 +47,7 @@ along with this program. If not, see .*/
}
.channel-guide-schedule-row{
- height: 2.2em;
+ height: 3.4em;
}
.channel-guide-channel-list-entry {
@@ -67,15 +67,20 @@ along with this program. If not, see .*/
.channel-guide-schedule-track {
display: flex;
+ position: relative;
}
.channel-guide-schedule-entry {
display: flex;
justify-content: center;
align-items: center;
+ overflow: hidden;
+ position: absolute;
}
.channel-guide-schedule-entry h3 {
margin: 0;
+ text-overflow: ellipsis;
+ overflow: hidden;
text-wrap: nowrap;
}
\ No newline at end of file
diff --git a/www/css/theme/the-network-classic.css b/www/css/theme/the-network-classic.css
index 5d760f6..2ab84d6 100644
--- a/www/css/theme/the-network-classic.css
+++ b/www/css/theme/the-network-classic.css
@@ -393,6 +393,20 @@ input.control-prompt, input.control-prompt:focus{
border-bottom: 1px solid var(--accent0);
}
+.channel-guide-schedule-entry{
+ padding: 0 0.7em;
+ background-color: var(--bg1);
+ border-left: 1px solid var(--accent0);
+}
+
+.channel-guide-schedule-entry.starts-before{
+ border-left: none;
+}
+
+.channel-guide-schedule-entry.last-ends-before{
+ border-right: 1px solid var(--accent0);
+}
+
/* channel settings */
.channel-info-label{
color: var(--accent1-alt0);
diff --git a/www/js/channelGuide.js b/www/js/channelGuide.js
index b2fe286..cc9039e 100644
--- a/www/js/channelGuide.js
+++ b/www/js/channelGuide.js
@@ -19,6 +19,9 @@ class ChannelGuide{
//define property to hold refresh timer
this.refreshTimer;
+ //define property to hold schedule cache
+ this.cache;
+
//Grab DOM Nodes
this.scheduleIndex = document.querySelector('#channel-guide-schedule-index');
this.channelList = document.querySelector('#channel-guide-channel-list');
@@ -28,14 +31,17 @@ class ChannelGuide{
this.refreshList();
}
- async refreshList(){
- //Fetch latest channel list and render it to the schedule page
- this.renderList(await utils.ajax.getChannels());
+ async refreshList(now = new Date()){
+ //Freshen up the local schedule cache
+ this.cache = await utils.ajax.getChannels();
+
+ //render the freshly pulled schedule data to the page
+ this.renderList(this.cache, now);
}
renderList(schedule, now = new Date()){
this.renderIndex(now);
- this.renderChannelList(schedule, now);
+ this.renderChannelList(schedule);
this.renderSchedule(schedule, now);
//if we've got a job to refresh the list
@@ -70,7 +76,7 @@ class ChannelGuide{
}
}
- renderChannelList(schedule, now = new Date()){
+ renderChannelList(schedule){
//Clean out channel list
this.channelList.innerHTML = '';
@@ -96,27 +102,24 @@ class ChannelGuide{
//Clear out the schedule
this.scheduledMediaDiv.innerHTML = '';
+ schedule = this.fillDeadAir(schedule, now);
+
//Iterate through all of the received channels
for(const channel of schedule){
+
//Create a div to hold all of the current channels entries
const channelTrack = document.createElement('div');
- channelTrack.classList.add('channel-guide-schedule-track');
+ channelTrack.classList.add('channel-guide-schedule-track', 'channel-guide-schedule-row');
//For every scheduled video
- for(const entry of channel.schedule){
- //Create div for current schedule entry
- const entryDiv = document.createElement('div');
- entryDiv.classList.add('channel-guide-schedule-entry', 'channel-guide-schedule-row');
-
- //Throw down an entry label
- const entryLabel = document.createElement('h3');
- entryLabel.textContent = utils.unescapeEntities(entry.title);
-
- //Assemble the entry
- entryDiv.appendChild(entryLabel);
+ for(const entryIndex in channel.schedule){
+ //Get entry by index
+ const entry = channel.schedule[entryIndex];
+ //Check if this is the last item
+ const last = entryIndex == channel.schedule.length - 1;
//slot entry into schedule track
- channelTrack.appendChild(entryDiv);
+ channelTrack.appendChild(this.renderScheduleItem(entry, now, last));
}
//Inject channel track into schedule div
@@ -124,7 +127,74 @@ class ChannelGuide{
}
}
- renderScheduleItem(item){
+
+ fillDeadAir(schedule){
+ //For each video in the schedule
+ for(const video of schedule){
+
+ }
+
+ //Return processed schedule
+ return schedule;
+ }
+
+ renderScheduleItem(item, now = new Date(), last = false){
+ //Create div for current schedule entry
+ const entryDiv = document.createElement('div');
+ entryDiv.classList.add('channel-guide-schedule-entry', 'channel-guide-schedule-row');
+
+ //Throw down an entry label
+ const entryLabel = document.createElement('h3');
+ entryLabel.textContent = utils.unescapeEntities(item.title);
+
+ //calculate end epoch
+ const end = item.startTime + (item.duration * 1000);
+
+ //Place entryDiv by scheduled time
+ entryDiv.style.left = `${this.offsetByEpoch(item.startTime, now)}px`;
+ entryDiv.style.right = `${this.offsetByEpoch(end, now, true)}px`;
+
+ //if this started before the schedule time range
+ if(item.startTime < now.getTime()){
+ //mark it for css
+ entryDiv.classList.add('starts-before');
+ }
+
+ //if this is the last item and it ends before the schedule time range
+ if(last && end < now.getTime() + 5400000){
+ //mark it for css
+ entryDiv.classList.add('last-ends-before');
+ }
+
+ //Assemble the entry
+ entryDiv.appendChild(entryLabel);
+
+ //Return assembled entry div
+ return entryDiv;
+ }
+
+ offsetByEpoch(scheduleEpoch, now = new Date(), rightOffset = false){
+ //Calculate how many milliseconds after the current time our scheduled item is
+ const ms = scheduleEpoch - now.getTime();
+
+ //Calculate and return offset by milliseconds
+ return this.offsetByMilliseconds(ms, rightOffset, rightOffset);
+ }
+
+ offsetByMilliseconds(ms, rightOffset = false){
+ //Calculate place in schedule as float between 0 and 1 by deviding input by schedules range (90 minutes)
+ //Making sure to reverse value if rightOffset is thrown
+ const timeFloat = rightOffset ? 1 - ms / 5400000 : ms / 5400000;
+
+ //Get maximum position relative to the range itself
+ const offsetMax = this.scheduledMediaDiv.getBoundingClientRect().width;
+
+ //Calculate offset by timefloat and offset max
+ const offset = (offsetMax * timeFloat) < 0 ? 0 : (offsetMax * timeFloat);
+
+ //return position relative to parent, adding channel list width to left side to handle offset
+ return offset;
+
}
}