2950 lines
109 KiB
JavaScript
2950 lines
109 KiB
JavaScript
"use strict";
|
|
|
|
var devices = {
|
|
DESKTOP: 0,
|
|
MOBILE: 1,
|
|
};
|
|
|
|
var vod_platform = {
|
|
DIRECT: 0,
|
|
VIMEO: 1,
|
|
YOUTUBE: 2,
|
|
};
|
|
|
|
function
|
|
GetVODPlatformFromString(VODPlatformString)
|
|
{
|
|
var Result = null;
|
|
switch(VODPlatformString)
|
|
{
|
|
case "direct": Result = vod_platform.DIRECT; break;
|
|
case "vimeo": Result = vod_platform.VIMEO; break;
|
|
case "youtube": Result = vod_platform.YOUTUBE; break;
|
|
default: break;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
var focus_level = {
|
|
ITEM: 0,
|
|
IDENTIFIER: 1,
|
|
};
|
|
|
|
var menu_id = {
|
|
UNSET: -1,
|
|
MARKERS: 0,
|
|
QUOTES: 1,
|
|
REFERENCES: 2,
|
|
FILTER: 3,
|
|
VIEWS: 4,
|
|
LINK: 5,
|
|
CREDITS: 6,
|
|
COUNT: 7,
|
|
};
|
|
|
|
var trigger_id = {
|
|
KEYBOARD: 0,
|
|
MOUSE: 1,
|
|
};
|
|
|
|
var views = {
|
|
REGULAR: 0,
|
|
THEATRE: 1,
|
|
SUPERTHEATRE: 2,
|
|
};
|
|
|
|
// refsCallback: (optional)
|
|
// Will be called when the player enters a marker that has a `data-ref` attribute. The value of `data-ref` will be passed to the function.
|
|
// When leaving a marker that a `data-ref` attribute, and entering a marker without one (or not entering a new marker at all), the function will be called with `null`.
|
|
function Player(cineraElement, refsCallback) {
|
|
this.root = cineraElement;
|
|
this.container = this.root.querySelector(".cineraPlayerContainer")
|
|
|
|
this.originalTextContent = {
|
|
TitleQuotes: null,
|
|
TitleReferences: null,
|
|
TitleCredits: null,
|
|
EpisodePrev: null,
|
|
EpisodeNext: null,
|
|
};
|
|
|
|
this.prevEpisode = this.container.querySelector(".episodeMarker.prev");
|
|
if(this.prevEpisode) { this.originalTextContent.EpisodePrev = this.prevEpisode.firstChild.textContent; }
|
|
this.nextEpisode = this.container.querySelector(".episodeMarker.next");
|
|
if(this.nextEpisode) { this.originalTextContent.EpisodeNext = this.nextEpisode.firstChild.textContent; }
|
|
|
|
this.videoContainer = this.container.querySelector(".video_container");
|
|
this.refsCallback = refsCallback || function() {};
|
|
|
|
|
|
if (!(this.videoContainer.getAttribute("data-platform") || this.videoContainer.getAttribute("data-videoId"))) {
|
|
console.error("Expected to find data-platform and data-videoId attribute on", this.videoContainer, "for player initialized on", this.container);
|
|
throw new Error("Missing data-platform or data-videoId attribute.");
|
|
}
|
|
|
|
var colouredItems = this.container.querySelectorAll(".author, .member, .project");
|
|
for(var i = 0; i < colouredItems.length; ++i)
|
|
{
|
|
setTextLightness(colouredItems[i]);
|
|
}
|
|
|
|
var topicDots = this.root.querySelectorAll(".category");
|
|
for(var i = 0; i < topicDots.length; ++i)
|
|
{
|
|
setDotLightness(topicDots[i]);
|
|
}
|
|
|
|
this.titleBar = this.root.querySelector(".cineraMenus");
|
|
|
|
this.MenusFocused = {
|
|
MenuID: menu_id.UNSET,
|
|
Item: null,
|
|
Identifier: null,
|
|
};
|
|
|
|
this.Menus = [];
|
|
this.Menus.length = menu_id.COUNT;
|
|
this.Menus[menu_id.MARKERS] = {
|
|
Container: this.container.querySelector(".markers_container"),
|
|
Elements: null,
|
|
Item: { LastFocused: null, },
|
|
Scroll: { To: -1, Position: 0, },
|
|
};
|
|
this.Menus[menu_id.QUOTES] = {
|
|
Container: null,
|
|
Elements: null, // The "Source" part of each Item
|
|
Item: { LastFocused: null, },
|
|
Identifier: { LastFocused: null, },
|
|
Scroll: { To: -1, Position: 0, },
|
|
};
|
|
this.Menus[menu_id.REFERENCES] = {
|
|
Container: null,
|
|
Elements: null, // The "Source" part of each Item
|
|
Item: { LastFocused: null, },
|
|
Identifier: { LastFocused: null, },
|
|
Scroll: { To: -1, Position: 0, },
|
|
};
|
|
this.Menus[menu_id.FILTER] = {
|
|
Container: null,
|
|
Elements: null,
|
|
Category: { LastFocused: null, },
|
|
Topic: { LastFocused: null, },
|
|
Medium: { LastFocused: null, },
|
|
Scroll: { To: -1, Position: 0, },
|
|
};
|
|
this.Menus[menu_id.VIEWS] = {
|
|
Toggler: null,
|
|
Container: null,
|
|
};
|
|
this.Menus[menu_id.LINK] = {
|
|
Container: null,
|
|
};
|
|
this.Menus[menu_id.CREDITS] = {
|
|
Container: null,
|
|
Item: { LastFocused: null, },
|
|
Scroll: { To: -1, Position: 0, },
|
|
};
|
|
|
|
this.initTitleBar();
|
|
this.Menus[menu_id.MARKERS].Elements = this.Menus[menu_id.MARKERS].Container.querySelectorAll(".marker");
|
|
|
|
// NOTE(matt): All the originalTextContent values must be set by this point, because the player's construction may need them
|
|
if(CineraProps.IsMobile)
|
|
{
|
|
this.InitMobileStyle();
|
|
}
|
|
|
|
this.markers = [];
|
|
var markerEls = this.Menus[menu_id.MARKERS].Elements;
|
|
if (markerEls.length == 0) {
|
|
console.error("No markers found in", this.Menus[menu_id.MARKERS].Container, "for player initialized on", this.container);
|
|
throw new Error("Missing markers.");
|
|
}
|
|
for (var i = 0; i < markerEls.length; ++i) {
|
|
var markerEl = markerEls[i];
|
|
var marker = {
|
|
timestamp: parseFloat(markerEl.getAttribute("data-timestamp")),
|
|
ref: markerEl.getAttribute("data-ref"),
|
|
endTime: (i < markerEls.length - 1 ? parseFloat(markerEls[i+1].getAttribute("data-timestamp")) : null),
|
|
el: markerEl,
|
|
fadedProgress: markerEl.querySelector(".progress.faded"),
|
|
progress: markerEl.querySelector(".progress.main"),
|
|
hoverx: null
|
|
};
|
|
marker.el.addEventListener("click", this.onMarkerClick.bind(this, marker));
|
|
marker.el.addEventListener("mousemove", this.onMarkerMouseMove.bind(this, marker));
|
|
marker.el.addEventListener("mouseenter", this.onMarkerMouseEnter.bind(this, marker));
|
|
marker.el.addEventListener("mouseleave", this.onMarkerMouseLeave.bind(this, marker));
|
|
this.markers.push(marker);
|
|
}
|
|
|
|
this.vod_platform = GetVODPlatformFromString(this.videoContainer.getAttribute("data-platform"));
|
|
this.currentMarker = null;
|
|
this.currentMarkerIdx = null;
|
|
|
|
this.platformPlayer = null;
|
|
this.platformPlayerReady = false;
|
|
|
|
this.duration = null;
|
|
this.playing = false;
|
|
this.shouldPlay = false;
|
|
this.buffering = false;
|
|
this.pauseAfterBuffer = false;
|
|
this.speed = 1;
|
|
this.currentTime = -1;
|
|
this.desiredTime = -1;
|
|
|
|
this.nextFrame = null;
|
|
this.looping = false;
|
|
|
|
this.Menus[menu_id.MARKERS].Container.addEventListener("wheel", function(ev) {
|
|
this.Menus[menu_id.MARKERS].Scroll.To = -1;
|
|
}.bind(this));
|
|
|
|
Player.initializePlatform(this.vod_platform, this.onPlatformReady.bind(this));
|
|
|
|
this.updateSize();
|
|
|
|
this.cineraViewStorageItem = "cineraView";
|
|
if(this.Menus[menu_id.VIEWS].Toggler && localStorage.getItem(this.cineraViewStorageItem))
|
|
{
|
|
this.toggleTheatreMode();
|
|
}
|
|
|
|
FlipClear();
|
|
|
|
this.resume();
|
|
|
|
InitScrollEventListener(this.root, CineraProps.IsMobile, null);
|
|
|
|
this.lastTimestampStorageItem = "cineraTimecode_" + window.location.pathname;
|
|
var lastTimestamp;
|
|
if(location.hash) {
|
|
this.setTimeThenPlay(location.hash.startsWith('#') ? location.hash.substr(1) : location.hash);
|
|
}
|
|
else if(lastTimestamp = localStorage.getItem(this.lastTimestampStorageItem))
|
|
{
|
|
this.setTimeThenPlay(lastTimestamp);
|
|
}
|
|
}
|
|
|
|
Player.prototype.addMenuTogglingMouseListeners = function(MenuID)
|
|
{
|
|
var player = this;
|
|
var menuToggler = player.Menus[MenuID].Container.closest(".menu");
|
|
menuToggler.addEventListener("mouseenter", function(ev) {
|
|
player.handleMenuTogglerInteraction(this, ev.type);
|
|
})
|
|
menuToggler.addEventListener("mouseleave", function(ev) {
|
|
player.handleMenuTogglerInteraction(this, ev.type);
|
|
})
|
|
menuToggler.addEventListener("click", function(ev) {
|
|
player.handleMenuTogglerInteraction(this, ev.type);
|
|
})
|
|
}
|
|
|
|
Player.prototype.addReferencesOrQuotesMouseListeners = function(MenuID)
|
|
{
|
|
var player = this;
|
|
var Items = player.Menus[MenuID].Container.querySelectorAll(".ref");
|
|
for(var i = 0; i < Items.length; ++i)
|
|
{
|
|
Items[i].addEventListener("mouseenter", function(ev) {
|
|
player.mouseOverReferencesOrQuotes(MenuID, this);
|
|
})
|
|
};
|
|
|
|
// The "Source" part of each Item
|
|
player.Menus[MenuID].Elements = player.Menus[MenuID].Container.querySelectorAll(".refs .ref");
|
|
for (var i = 0; i < player.Menus[MenuID].Elements.length; ++i) {
|
|
player.Menus[MenuID].Elements[i].addEventListener("click", function(ev) {
|
|
player.pause();
|
|
});
|
|
}
|
|
|
|
var Timecodes = player.Menus[MenuID].Container.querySelectorAll(".refs .ref .ref_indices .timecode");
|
|
for (var i = 0; i < Timecodes.length; ++i) {
|
|
Timecodes[i].addEventListener("click", function(ev) {
|
|
var time = ev.currentTarget.getAttribute("data-timestamp");
|
|
mouseSkipToTimecode(player, time, ev);
|
|
player.setScroller(player.Menus[MenuID], this.closest(".ref"), true, false);
|
|
});
|
|
|
|
Timecodes[i].addEventListener("mouseenter", function(ev) {
|
|
player.mouseOverReferenceOrQuoteIdentifier(MenuID, this);
|
|
});
|
|
}
|
|
}
|
|
|
|
Player.prototype.initMenu_Quotes = function()
|
|
{
|
|
var player = this;
|
|
var MenuID = menu_id.QUOTES;
|
|
player.Menus[MenuID].Container = player.titleBar.querySelector(".quotes_container");
|
|
if(player.Menus[MenuID].Container)
|
|
{
|
|
player.originalTextContent.TitleQuotes = player.Menus[MenuID].Container.previousElementSibling.textContent;
|
|
player.addReferencesOrQuotesMouseListeners(MenuID);
|
|
player.addMenuTogglingMouseListeners(MenuID);
|
|
}
|
|
}
|
|
|
|
Player.prototype.initMenu_References = function()
|
|
{
|
|
var player = this;
|
|
var MenuID = menu_id.REFERENCES;
|
|
player.Menus[MenuID].Container = player.titleBar.querySelector(".references_container");
|
|
if(player.Menus[MenuID].Container)
|
|
{
|
|
player.originalTextContent.TitleReferences = player.Menus[MenuID].Container.previousElementSibling.textContent;
|
|
player.addReferencesOrQuotesMouseListeners(MenuID);
|
|
player.addMenuTogglingMouseListeners(MenuID);
|
|
}
|
|
}
|
|
|
|
Player.prototype.initMenu_Filter = function()
|
|
{
|
|
var player = this;
|
|
var MenuID = menu_id.FILTER;
|
|
player.Menus[MenuID].Container = player.titleBar.querySelector(".filter_container");
|
|
if(player.Menus[MenuID].Container)
|
|
{
|
|
player.filter = player.Menus[MenuID].Container.parentNode;
|
|
|
|
player.filterModeElement = player.filter.querySelector(".filter_mode");
|
|
player.filterModeElement.addEventListener("click", function(ev) {
|
|
ev.stopPropagation();
|
|
player.toggleFilterMode();
|
|
});
|
|
|
|
player.filterMode = player.filterModeElement.classList[1];
|
|
player.Menus[menu_id.FILTER].Elements = player.filter.querySelectorAll(".filter_content");
|
|
|
|
player.filterInitState = new Object();
|
|
player.filterState = new Object();
|
|
for(var i = 0; i < player.Menus[menu_id.FILTER].Elements.length; ++i)
|
|
{
|
|
var Item = player.Menus[menu_id.FILTER].Elements[i];
|
|
Item.addEventListener("mouseenter", function(ev) {
|
|
player.navigateFilter(this);
|
|
})
|
|
|
|
Item.addEventListener("click", function(ev) {
|
|
ev.stopPropagation();
|
|
player.filterItemToggle(this);
|
|
});
|
|
|
|
var filterItemName = Item.classList.item(1);
|
|
if(Item.parentNode.classList.contains("filter_topics"))
|
|
{
|
|
player.filterInitState[filterItemName] = { "type" : "topic", "off": (Item.classList.item(2) == "off") };
|
|
player.filterState[filterItemName] = { "type" : "topic", "off": (Item.classList.item(2) == "off") };
|
|
}
|
|
else
|
|
{
|
|
player.filterInitState[filterItemName] = { "type" : "medium", "off": (Item.classList.item(2) == "off") };
|
|
player.filterState[filterItemName] = { "type" : "medium", "off": (Item.classList.item(2) == "off") };
|
|
}
|
|
}
|
|
|
|
player.addMenuTogglingMouseListeners(MenuID);
|
|
}
|
|
}
|
|
|
|
Player.prototype.initMenu_Views = function()
|
|
{
|
|
var player = this;
|
|
var MenuID = menu_id.VIEWS;
|
|
player.Menus[MenuID].Toggler = player.titleBar.querySelector(".views");
|
|
if(player.Menus[MenuID].Toggler && !CineraProps.IsMobile)
|
|
{
|
|
player.Menus[MenuID].Container = player.Menus[MenuID].Toggler.querySelector(".views_container");
|
|
player.Menus[MenuID].Toggler.addEventListener("mouseenter", function(ev) {
|
|
player.handleMouseOverViewsMenu();
|
|
});
|
|
player.Menus[MenuID].Toggler.addEventListener("mouseleave", function(ev) {
|
|
player.Menus[MenuID].Container.classList.remove("visible");
|
|
player.MenusFocused.MenuID = menu_id.UNSET;
|
|
});
|
|
|
|
player.viewItems = player.Menus[MenuID].Toggler.querySelectorAll(".view");
|
|
for(var i = 0; i < player.viewItems.length; ++i)
|
|
{
|
|
player.viewItems[i].addEventListener("click", function(ev) {
|
|
switch(this.getAttribute("data-id"))
|
|
{
|
|
case "regular":
|
|
case "theatre":
|
|
{
|
|
player.toggleTheatreMode();
|
|
} break;
|
|
case "super":
|
|
{
|
|
player.toggleSuperTheatreMode();
|
|
} break;
|
|
}
|
|
});
|
|
}
|
|
|
|
player.addMenuTogglingMouseListeners(MenuID);
|
|
}
|
|
}
|
|
|
|
Player.prototype.initMenu_Link = function()
|
|
{
|
|
var player = this;
|
|
var MenuID = menu_id.LINK;
|
|
player.Menus[MenuID].Container = player.titleBar.querySelector(".link_container");
|
|
if(player.Menus[MenuID].Container)
|
|
{
|
|
player.linkMode = player.Menus[MenuID].Container.querySelector("#cineraLinkMode");
|
|
player.link = player.Menus[MenuID].Container.querySelector("#cineraLink");
|
|
player.linkTimestamp = true;
|
|
|
|
player.linkMode.addEventListener("click", function(ev) {
|
|
ev.stopPropagation();
|
|
player.toggleLinkMode();
|
|
});
|
|
|
|
player.link.addEventListener("click", function(ev) {
|
|
player.CopyToClipboard(player.link);
|
|
player.toggleMenuVisibility(MenuID, trigger_id.MOUSE);
|
|
});
|
|
|
|
player.addMenuTogglingMouseListeners(MenuID);
|
|
}
|
|
}
|
|
|
|
Player.prototype.initMenu_Credits = function()
|
|
{
|
|
var player = this;
|
|
var MenuID = menu_id.CREDITS;
|
|
player.Menus[MenuID].Container = player.titleBar.querySelector(".credits_container");
|
|
if(player.Menus[MenuID].Container)
|
|
{
|
|
player.originalTextContent.TitleCredits = player.Menus[MenuID].Container.previousElementSibling.textContent;
|
|
|
|
var creditItems = player.Menus[MenuID].Container.querySelectorAll(".person, .support");
|
|
for(var i = 0; i < creditItems.length; ++i)
|
|
{
|
|
var creditItem = creditItems[i];
|
|
creditItem.addEventListener("mouseenter", function(ev) {
|
|
player.mouseOverCredits(this);
|
|
});
|
|
if(creditItem.tagName == "A")
|
|
{
|
|
creditItem.addEventListener("click", function(ev) {
|
|
player.pause();
|
|
});
|
|
}
|
|
}
|
|
|
|
player.addMenuTogglingMouseListeners(MenuID);
|
|
}
|
|
}
|
|
|
|
Player.prototype.initMenus = function()
|
|
{
|
|
this.initMenu_Quotes();
|
|
this.initMenu_References();
|
|
this.initMenu_Filter();
|
|
this.initMenu_Views();
|
|
this.initMenu_Link();
|
|
this.initMenu_Credits();
|
|
}
|
|
|
|
Player.prototype.initTitleBar = function()
|
|
{
|
|
if(this.titleBar)
|
|
{
|
|
this.initMenus();
|
|
|
|
this.helpButton = this.titleBar.querySelector(".cineraHelp");
|
|
this.helpDocumentation = this.helpButton.querySelector(".help_container");
|
|
BindHelp(this.helpButton, this.helpDocumentation);
|
|
}
|
|
}
|
|
|
|
// Start playing the video from the current position.
|
|
// If the player hasn't loaded yet, it will autoplay when ready.
|
|
Player.prototype.play = function() {
|
|
if (this.platformPlayerReady) {
|
|
if (!this.playing) {
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
this.platformPlayer.play();
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
this.platformPlayer.play();
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
this.platformPlayer.playVideo();
|
|
} break;
|
|
}
|
|
this.pauseAfterBuffer = false;
|
|
} else {
|
|
this.shouldPlay = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Pause the video at the current position.
|
|
// If the player hasn't loaded yet, it will not autoplay when ready. (This is the default)
|
|
Player.prototype.pause = function() {
|
|
if (this.platformPlayerReady) {
|
|
if (this.playing) {
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
this.platformPlayer.pause();
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
this.platformPlayer.pause();
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
this.platformPlayer.pauseVideo();
|
|
} break;
|
|
}
|
|
} else if (this.buffering) {
|
|
this.pauseAfterBuffer = true;
|
|
}
|
|
} else {
|
|
this.shouldPlay = false;
|
|
}
|
|
};
|
|
|
|
// Sets the current time then plays.
|
|
// If the player hasn't loaded yet, it will seek to this time when ready.
|
|
Player.prototype.setTimeThenPlay = function(time) {
|
|
this.desiredTime = time;
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
if (this.platformPlayerReady) {
|
|
this.desiredTime = Math.max(0, Math.min(this.desiredTime, this.duration));
|
|
this.platformPlayer.currentTime = this.desiredTime;
|
|
this.updateProgress();
|
|
this.play();
|
|
}
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
if (this.platformPlayerReady) {
|
|
this.desiredTime = Math.max(0, Math.min(this.desiredTime, this.duration));
|
|
var Parent = this;
|
|
this.platformPlayer.setCurrentTime(this.desiredTime)
|
|
.then(function() {
|
|
Parent.updateProgress();
|
|
Parent.play();
|
|
});
|
|
}
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
if (this.platformPlayerReady) {
|
|
this.desiredTime = Math.max(0, Math.min(this.desiredTime, this.duration));
|
|
this.platformPlayer.seekTo(this.desiredTime);
|
|
this.updateProgress();
|
|
this.play();
|
|
}
|
|
} break;
|
|
}
|
|
};
|
|
|
|
Player.prototype.jumpToNextMarker = function() {
|
|
var targetMarkerIdx = Math.min((this.currentMarkerIdx === null ? 0 : this.currentMarkerIdx + 1), this.markers.length-1);
|
|
var targetTime = this.markers[targetMarkerIdx].timestamp;
|
|
while(targetMarkerIdx < this.markers.length && this.markers[targetMarkerIdx].el.classList.contains("skip"))
|
|
{
|
|
++targetMarkerIdx;
|
|
targetTime = this.markers[targetMarkerIdx].timestamp;
|
|
}
|
|
this.setTimeThenPlay(targetTime);
|
|
};
|
|
|
|
Player.prototype.jumpToPrevMarker = function() {
|
|
var targetMarkerIdx = Math.max(0, (this.currentMarkerIdx === null ? 0 : this.currentMarkerIdx - 1));
|
|
var targetTime = this.markers[targetMarkerIdx].timestamp;
|
|
while(targetMarkerIdx >= 0 && this.markers[targetMarkerIdx].el.classList.contains("skip"))
|
|
{
|
|
--targetMarkerIdx;
|
|
targetTime = this.markers[targetMarkerIdx].timestamp;
|
|
}
|
|
this.setTimeThenPlay(targetTime);
|
|
};
|
|
|
|
function
|
|
GetHeightOfHideableElement(Element, UnhidingClass)
|
|
{
|
|
var Result = 0;
|
|
if(Element.classList.contains(UnhidingClass))
|
|
{
|
|
Result = Element.offsetHeight;
|
|
}
|
|
else
|
|
{
|
|
var ZOffset = Element.style.zOffset;
|
|
Element.style.zOffset = -1;
|
|
Element.classList.add(UnhidingClass);
|
|
|
|
Result = Element.offsetHeight;
|
|
|
|
Element.classList.remove(UnhidingClass);
|
|
Element.style.zOffset = ZOffset;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
function
|
|
GetWidthOfHideableElement(Element, UnhidingClass)
|
|
{
|
|
var Result = 0;
|
|
if(Element.classList.contains(UnhidingClass))
|
|
{
|
|
Result = Element.offsetWidth;
|
|
}
|
|
else
|
|
{
|
|
var ZOffset = Element.style.zOffset;
|
|
Element.style.zOffset = -1;
|
|
Element.classList.add(UnhidingClass);
|
|
|
|
Result = Element.offsetWidth;
|
|
|
|
Element.classList.remove(UnhidingClass);
|
|
Element.style.zOffset = ZOffset;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
function
|
|
ComputeHorizontalOffsetForMenu(Menu, Toggler, VideoContainerDimX)
|
|
{
|
|
var Result = 0;
|
|
var MenuWidth = GetWidthOfHideableElement(Menu, "visible");
|
|
var TogglerWidth = Toggler.offsetWidth;
|
|
|
|
var TogglerOffset = Toggler.offsetLeft;
|
|
var Result = TogglerOffset + (TogglerWidth / 2) - (MenuWidth / 2);
|
|
|
|
var Protrusion = MenuWidth + Result - VideoContainerDimX;
|
|
if(Protrusion > 0)
|
|
{
|
|
Result -= Protrusion;
|
|
}
|
|
|
|
if(Result < 0)
|
|
{
|
|
Result = 0;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
function
|
|
ComputeVerticalOffsetForMenu(Menu, Toggler, VideoContainerDimY)
|
|
{
|
|
var Result = 0;
|
|
var MenuHeight = GetHeightOfHideableElement(Menu, "visible");
|
|
var TogglerHeight = Toggler.offsetHeight;
|
|
|
|
var TogglerOffset = Toggler.offsetTop;
|
|
var Result = TogglerOffset + (TogglerHeight / 2) - (MenuHeight / 2);
|
|
|
|
var LowerProtrusion = MenuHeight + Result - VideoContainerDimY;
|
|
if(LowerProtrusion > 0)
|
|
{
|
|
Result -= LowerProtrusion;
|
|
}
|
|
|
|
if(Result < 0)
|
|
{
|
|
Result = 0;
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
function sizeAndPositionMenuContainer(TitleBar, SizerElement, Menu)
|
|
{
|
|
if(Menu)
|
|
{
|
|
var Toggler = Menu.parentElement;
|
|
|
|
var TitleBarDimX = TitleBar.offsetWidth;
|
|
var TitleBarDimY = TitleBar.offsetHeight;
|
|
var SizerElementDimX = SizerElement.offsetWidth;
|
|
var SizerElementDimY = SizerElement.offsetHeight;
|
|
|
|
var ContainerDimX = SizerElementDimX;
|
|
var ContainerDimY = SizerElementDimY;
|
|
|
|
switch(CineraProps.O)
|
|
{
|
|
case orientations.PORTRAIT:
|
|
{
|
|
Menu.style.borderTopWidth = 0;
|
|
Menu.style.borderTopStyle = "none";
|
|
Menu.style.borderRightWidth = "1px";
|
|
Menu.style.borderRightStyle = "solid";
|
|
Menu.style.borderLeftWidth = "1px";
|
|
Menu.style.borderLeftStyle = "solid";
|
|
|
|
Menu.style.maxWidth = ContainerDimX + "px";
|
|
ContainerDimY -= TitleBarDimY;
|
|
Menu.style.maxHeight = ContainerDimY + "px";
|
|
|
|
var MenuHorizontalOffset = ComputeHorizontalOffsetForMenu(Menu, Toggler, SizerElementDimX);
|
|
|
|
Menu.style.top = TitleBarDimY + "px";
|
|
Menu.style.left = MenuHorizontalOffset + "px";
|
|
} break;
|
|
case orientations.LANDSCAPE_LEFT:
|
|
{
|
|
Menu.style.borderTopWidth = "1px";
|
|
Menu.style.borderTopStyle = "solid";
|
|
Menu.style.borderRightWidth = "1px";
|
|
Menu.style.borderRightStyle = "solid";
|
|
Menu.style.borderLeftWidth = 0;
|
|
Menu.style.borderLeftStyle = "none";
|
|
|
|
ContainerDimX -= TitleBarDimX;
|
|
Menu.style.maxWidth = ContainerDimX + "px";
|
|
Menu.style.maxHeight = ContainerDimY + "px";
|
|
|
|
var MenuVerticalOffset = ComputeVerticalOffsetForMenu(Menu, Toggler, SizerElementDimY);
|
|
|
|
Menu.style.top = MenuVerticalOffset + "px";
|
|
Menu.style.left = TitleBarDimX + "px";
|
|
} break;
|
|
case orientations.LANDSCAPE_RIGHT:
|
|
{
|
|
Menu.style.borderTopWidth = "1px";
|
|
Menu.style.borderTopStyle = "solid";
|
|
Menu.style.borderRightWidth = 0;
|
|
Menu.style.borderRightStyle = "none";
|
|
Menu.style.borderLeftWidth = "1px";
|
|
Menu.style.borderLeftStyle = "solid";
|
|
|
|
ContainerDimX -= TitleBarDimX;
|
|
Menu.style.maxWidth = ContainerDimX + "px";
|
|
Menu.style.maxHeight = ContainerDimY + "px";
|
|
|
|
var MenuVerticalOffset = ComputeVerticalOffsetForMenu(Menu, Toggler, SizerElementDimY);
|
|
var MenuWidth = GetWidthOfHideableElement(Menu, "visible");
|
|
|
|
Menu.style.top = MenuVerticalOffset + "px";
|
|
Menu.style.left = -MenuWidth + "px";
|
|
} break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
function
|
|
ComputeTallest(Elements, UnhidingClass)
|
|
{
|
|
var Result = null;
|
|
for(var i = 0; i < Elements.length; ++i)
|
|
{
|
|
var This = Elements[i];
|
|
var Height = UnhidingClass ? GetHeightOfHideableElement(This, UnhidingClass) : This.offsetHeight;
|
|
if(Height > Result)
|
|
{
|
|
Result = Height;
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
function
|
|
ComputeAndSetTallest(Selector, Elements, UnhidingClass)
|
|
{
|
|
var Result;
|
|
Selector.style.height = "unset";
|
|
Result = ComputeTallest(Elements, UnhidingClass);
|
|
Selector.style.height = Result + "px";
|
|
return Result;
|
|
}
|
|
|
|
Player.prototype.ApplyMobileStyle = function(VideoContainer)
|
|
{
|
|
var WindowDim = DeriveReliableWindowDimensions();
|
|
var MaxWidth = MaxWidthOfElement(this.root, WindowDim);
|
|
var MaxHeight = MaxHeightOfElement(this.root, WindowDim);
|
|
|
|
var IndicesBar = this.Menus[menu_id.MARKERS].Container;
|
|
|
|
var Markers = IndicesBar.querySelector(".markers");
|
|
var CineraContentWidth = MaxWidth;
|
|
|
|
var EpisodeMarkers = IndicesBar.querySelectorAll(".episodeMarker");
|
|
for(var i = 0; i < EpisodeMarkers.length; ++i)
|
|
{
|
|
CineraContentWidth -= EpisodeMarkers[i].offsetWidth;
|
|
}
|
|
|
|
switch(CineraProps.O)
|
|
{
|
|
case orientations.PORTRAIT:
|
|
{
|
|
this.root.style.flexDirection = "column";
|
|
this.titleBar.style.flexDirection = "row";
|
|
} break;
|
|
case orientations.LANDSCAPE_LEFT:
|
|
{
|
|
this.root.style.flexDirection = "row";
|
|
this.titleBar.style.flexDirection = "column-reverse";
|
|
CineraContentWidth -= this.titleBar.offsetWidth;
|
|
} break;
|
|
case orientations.LANDSCAPE_RIGHT:
|
|
{
|
|
this.root.style.flexDirection = "row-reverse";
|
|
this.titleBar.style.flexDirection = "column";
|
|
CineraContentWidth -= this.titleBar.offsetWidth;
|
|
} break;
|
|
}
|
|
|
|
var HeightOfTallestIndex;
|
|
if(MobileCineraContentRule !== undefined)
|
|
{
|
|
MobileCineraContentRule.style.width = CineraContentWidth + "px";
|
|
HeightOfTallestIndex = ComputeAndSetTallest(MobileCineraContentRule, this.Menus[menu_id.MARKERS].Elements, "current");
|
|
IndicesBar.style.height = HeightOfTallestIndex + "px";
|
|
Markers.style.width = CineraContentWidth + "px";
|
|
}
|
|
|
|
var VideoMaxDimX = MaxWidth;
|
|
var VideoMaxDimY = MaxHeight;
|
|
var MinimumVideoHeight = 32;
|
|
if(MaxHeight - HeightOfTallestIndex > MinimumVideoHeight)
|
|
{
|
|
VideoMaxDimY -= HeightOfTallestIndex;
|
|
}
|
|
|
|
switch(CineraProps.O)
|
|
{
|
|
case orientations.PORTRAIT:
|
|
{
|
|
VideoMaxDimY -= this.titleBar.offsetHeight;
|
|
} break;
|
|
case orientations.LANDSCAPE_LEFT:
|
|
case orientations.LANDSCAPE_RIGHT:
|
|
{
|
|
VideoMaxDimX -= this.titleBar.offsetWidth;
|
|
} break;
|
|
}
|
|
|
|
var VideoDimYFromMaxX = VideoMaxDimX * 9 / 16;
|
|
var VideoDimXFromMaxY = VideoMaxDimY * 16 / 9;
|
|
|
|
var VideoDimX = 0;
|
|
var VideoDimY = 0;
|
|
if(VideoDimXFromMaxY > VideoMaxDimX)
|
|
{
|
|
VideoDimX = Math.floor(VideoMaxDimX);
|
|
VideoDimY = Math.floor(VideoDimYFromMaxX);
|
|
}
|
|
else if(VideoDimYFromMaxX > VideoMaxDimY)
|
|
{
|
|
VideoDimY = Math.floor(VideoMaxDimY);
|
|
VideoDimX = Math.floor(VideoDimXFromMaxY);
|
|
}
|
|
else
|
|
{
|
|
VideoDimX = Math.floor(VideoMaxDimX);
|
|
VideoDimY = Math.floor(VideoDimYFromMaxX);
|
|
}
|
|
|
|
VideoContainer.style.width = VideoDimX + "px";
|
|
VideoContainer.style.height = VideoDimY + "px";
|
|
|
|
sizeAndPositionMenuContainer(this.titleBar, this.root, this.Menus[menu_id.QUOTES].Container);
|
|
sizeAndPositionMenuContainer(this.titleBar, this.root, this.Menus[menu_id.REFERENCES].Container);
|
|
sizeAndPositionMenuContainer(this.titleBar, this.root, this.Menus[menu_id.FILTER].Container);
|
|
sizeAndPositionMenuContainer(this.titleBar, this.root, this.Menus[menu_id.LINK].Container);
|
|
sizeAndPositionMenuContainer(this.titleBar, this.root, this.Menus[menu_id.CREDITS].Container);
|
|
}
|
|
|
|
Player.prototype.IconifyMenuTogglers = function()
|
|
{
|
|
if(this.Menus[menu_id.QUOTES].Container)
|
|
{
|
|
this.Menus[menu_id.QUOTES].Container.previousElementSibling.textContent = '\u{1F5E9}';
|
|
}
|
|
|
|
if(this.Menus[menu_id.REFERENCES].Container)
|
|
{
|
|
this.Menus[menu_id.REFERENCES].Container.previousElementSibling.textContent = '\u{1F4D6}';
|
|
}
|
|
|
|
if(this.Menus[menu_id.CREDITS].Container)
|
|
{
|
|
this.Menus[menu_id.CREDITS].Container.previousElementSibling.textContent = '\u{1F46A}';
|
|
}
|
|
|
|
if(this.Menus[menu_id.VIEWS].Toggler)
|
|
{
|
|
this.Menus[menu_id.VIEWS].Toggler.remove();
|
|
this.Menus[menu_id.VIEWS].Toggler = null;
|
|
}
|
|
}
|
|
|
|
Player.prototype.InitMobileControls = function()
|
|
{
|
|
var rightmost = {};
|
|
this.Menus[menu_id.MARKERS].Container.style.height = "auto";
|
|
var episodeMarkerFirst = this.Menus[menu_id.MARKERS].Container.querySelector(".episodeMarker.first");
|
|
var episodeMarkerPrev = this.Menus[menu_id.MARKERS].Container.querySelector(".episodeMarker.prev");
|
|
var episodeMarkerNext = this.Menus[menu_id.MARKERS].Container.querySelector(".episodeMarker.next");
|
|
var episodeMarkerLast = this.Menus[menu_id.MARKERS].Container.querySelector(".episodeMarker.last");
|
|
|
|
if(episodeMarkerPrev) { episodeMarkerPrev.firstChild.textContent = '\u{23EE}'; }
|
|
if(episodeMarkerNext) { episodeMarkerNext.firstChild.textContent = '\u{23ED}'; rightmost = episodeMarkerNext; }
|
|
else if (episodeMarkerLast) { rightmost = episodeMarkerLast; }
|
|
|
|
var controlPrevTimestamp = document.createElement("a");
|
|
controlPrevTimestamp.classList.add("episodeMarker");
|
|
controlPrevTimestamp.classList.add("prevTimestamp");
|
|
var controlPrevTimestampContent = document.createElement("div");
|
|
controlPrevTimestampContent.appendChild(document.createTextNode('\u{25C0}'));
|
|
controlPrevTimestamp.appendChild(controlPrevTimestampContent);
|
|
|
|
var markers = this.Menus[menu_id.MARKERS].Container.querySelector(".markers");
|
|
this.Menus[menu_id.MARKERS].Container.insertBefore(controlPrevTimestamp, markers);
|
|
|
|
var controlNextTimestamp = document.createElement("a");
|
|
controlNextTimestamp.classList.add("episodeMarker");
|
|
controlNextTimestamp.classList.add("nextTimestamp");
|
|
var controlNextTimestampContent = document.createElement("div");
|
|
controlNextTimestampContent.appendChild(document.createTextNode('\u{25B6}'));
|
|
controlNextTimestamp.appendChild(controlNextTimestampContent);
|
|
|
|
if(rightmost)
|
|
{
|
|
this.Menus[menu_id.MARKERS].Container.insertBefore(controlNextTimestamp, rightmost);
|
|
}
|
|
else
|
|
{
|
|
this.Menus[menu_id.MARKERS].Container.appendChild(controlNextTimestamp);
|
|
}
|
|
}
|
|
|
|
Player.prototype.ConnectMobileControls = function()
|
|
{
|
|
var player = this;
|
|
var ControlPrevTimestamp = this.Menus[menu_id.MARKERS].Container.querySelector(".episodeMarker.prevTimestamp");
|
|
ControlPrevTimestamp.addEventListener("click", function(ev) {
|
|
player.jumpToPrevMarker();
|
|
});
|
|
var ControlNextTimestamp = this.Menus[menu_id.MARKERS].Container.querySelector(".episodeMarker.nextTimestamp");
|
|
ControlNextTimestamp.addEventListener("click", function(ev) {
|
|
player.jumpToNextMarker();
|
|
});
|
|
}
|
|
|
|
Player.prototype.InitMobileStyle = function()
|
|
{
|
|
this.root.classList.add("mobile");
|
|
this.IconifyMenuTogglers();
|
|
this.InitMobileControls();
|
|
this.ConnectMobileControls();
|
|
this.ApplyMobileStyle(this.videoContainer);
|
|
}
|
|
|
|
// Call this after changing the size of the video container in order to update the platform player.
|
|
Player.prototype.updateSize = function() {
|
|
var width = 0;
|
|
var height = 0;
|
|
CineraProps.O = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile);
|
|
if(!CineraProps.IsMobile)
|
|
{
|
|
var VisibleArea = MaxDimensionsOfElement(this.container, GetWindowDim(false));
|
|
var AvailableHeight = VisibleArea.Y - this.titleBar.offsetHeight;
|
|
var VerticalScrollBarWidth = this.Menus[menu_id.MARKERS].Container.offsetWidth - this.Menus[menu_id.MARKERS].Container.clientWidth;
|
|
width = VisibleArea.X - (this.Menus[menu_id.MARKERS].Container.scrollWidth + VerticalScrollBarWidth);
|
|
height = width / 16 * 9; // TODO(matt): Get the aspect ratio from the video itself?
|
|
if(height > AvailableHeight)
|
|
{
|
|
height = AvailableHeight;
|
|
width = height / 9 * 16;
|
|
}
|
|
this.Menus[menu_id.MARKERS].Container.style.height = height + "px";
|
|
|
|
var VacantPixelsBelowMenus = 4;
|
|
var MenuMaxHeight = height - VacantPixelsBelowMenus;
|
|
MenuContainerRule.style.maxHeight = MenuMaxHeight + "px";
|
|
}
|
|
else
|
|
{
|
|
this.ApplyMobileStyle(this.videoContainer);
|
|
width = this.videoContainer.offsetWidth;
|
|
height = this.videoContainer.offsetHeight;
|
|
}
|
|
|
|
if(this.platformPlayerReady)
|
|
{
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
this.platformPlayer.setAttribute("width", Math.floor(width));
|
|
this.platformPlayer.setAttribute("height", Math.floor(height));
|
|
} break;
|
|
case vod_platform.VIMEO: break; // NOTE(matt): It responds automatically
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
this.platformPlayer.setSize(Math.floor(width), Math.floor(height));
|
|
} break;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function
|
|
DelayedUpdateSize(player)
|
|
{
|
|
player.updateSize();
|
|
}
|
|
|
|
// Stops the per-frame work that the player does. Call when you want to hide or get rid of the player.
|
|
Player.prototype.halt = function() {
|
|
this.pause();
|
|
this.looping = false;
|
|
if (this.nextFrame) {
|
|
cancelAnimationFrame(this.nextFrame);
|
|
this.nextFrame = null;
|
|
}
|
|
}
|
|
|
|
// Resumes the per-frame work that the player does. Call when you want to show the player again after hiding.
|
|
Player.prototype.resume = function() {
|
|
this.looping = true;
|
|
if (!this.nextFrame) {
|
|
this.doFrame();
|
|
}
|
|
}
|
|
|
|
Player.initializePlatform = function(platform_id, callback) {
|
|
switch(platform_id)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
case vod_platform.VIMEO:
|
|
{
|
|
callback();
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
if(window.YT && window.YT.loaded)
|
|
{
|
|
callback()
|
|
}
|
|
else
|
|
{
|
|
if (window.APYoutubeAPIReady === undefined) {
|
|
window.APYoutubeAPIReady = false;
|
|
window.APCallbacks = (callback ? [callback] : []);
|
|
window.onYouTubeIframeAPIReady = function() {
|
|
window.APYoutubeAPIReady = true;
|
|
for (var i = 0; i < APCallbacks.length; ++i) {
|
|
APCallbacks[i]();
|
|
}
|
|
};
|
|
} else if (window.APYoutubeAPIReady === false) {
|
|
window.APCallbacks.push(callback);
|
|
} else if (window.APYoutubeAPIReady === true) {
|
|
callback();
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
|
|
// END PUBLIC INTERFACE
|
|
|
|
Player.prototype.onMarkerClick = function(marker, ev) {
|
|
if(!marker.el.classList.contains("skip"))
|
|
{
|
|
var time = marker.timestamp;
|
|
if (this.currentMarker == marker && marker.hoverx !== null) {
|
|
time += (marker.endTime - marker.timestamp) * marker.hoverx;
|
|
}
|
|
this.setTimeThenPlay(time);
|
|
}
|
|
};
|
|
|
|
Player.prototype.onMarkerMouseMove = function(marker, ev) {
|
|
if(!marker.el.classList.contains("skip"))
|
|
{
|
|
if (this.currentMarker == marker) {
|
|
var CineraContent = this.currentMarker.el.querySelector(".cineraContent");
|
|
marker.hoverx = (ev.pageX - getElementXOffsetFromPage(CineraContent)) / CineraContent.offsetWidth;
|
|
}
|
|
}
|
|
};
|
|
|
|
Player.prototype.onMarkerMouseEnter = function(marker, ev) {
|
|
if(!marker.el.classList.contains("skip"))
|
|
{
|
|
if(this.MenusFocused.MenuID == menu_id.UNSET || this.MenusFocused.MenuID == menu_id.MARKERS)
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.MARKERS, this.Menus[menu_id.MARKERS].Item, marker.el);
|
|
}
|
|
}
|
|
};
|
|
|
|
Player.prototype.onMarkerMouseLeave = function(marker, ev) {
|
|
if(!marker.el.classList.contains("skip"))
|
|
{
|
|
marker.hoverx = null;
|
|
var CurrentFocus = this.MenusFocused.MenuID;
|
|
this.unfocusUIElement(focus_level.ITEM);
|
|
if(CurrentFocus != menu_id.MARKERS)
|
|
{
|
|
this.MenusFocused.MenuID = CurrentFocus;
|
|
}
|
|
}
|
|
};
|
|
|
|
function
|
|
computeCentreScrollOffset(container, targetTop, targetBottom)
|
|
{
|
|
var Result = 0;
|
|
var Bottom = targetBottom.offsetTop + targetBottom.offsetHeight;
|
|
var Midpoint = (Bottom - targetTop.offsetTop) / 2.0;
|
|
Result += Midpoint - container.offsetHeight / 2.0
|
|
return Result;
|
|
}
|
|
|
|
Player.prototype.computeDesiredScrollTo = function(MenuEntity, targetTop, targetBottom, centre)
|
|
{
|
|
MenuEntity.Scroll.To = targetTop.offsetTop;
|
|
var container = MenuEntity.Container;
|
|
if(centre)
|
|
{
|
|
MenuEntity.Scroll.To += computeCentreScrollOffset(container, targetTop, targetBottom);
|
|
MenuEntity.Scroll.To = Math.max(0, Math.min(MenuEntity.Scroll.To, targetTop.offsetTop));
|
|
}
|
|
MenuEntity.Scroll.Position = container.scrollTop;
|
|
}
|
|
|
|
Player.prototype.setScrollerRanged = function(MenuEntity, targetTop, targetBottom, centre, calledEveryFrame) {
|
|
if(!calledEveryFrame || this.desiredTime >= 0)
|
|
{
|
|
this.computeDesiredScrollTo(MenuEntity, targetTop, targetBottom, centre);
|
|
}
|
|
}
|
|
|
|
Player.prototype.setScroller = function(MenuEntity, element, centre, calledEveryFrame) {
|
|
if(!calledEveryFrame || this.desiredTime >= 0)
|
|
{
|
|
this.computeDesiredScrollTo(MenuEntity, element, element, centre);
|
|
}
|
|
}
|
|
|
|
Player.prototype.updateProgress = function() {
|
|
var prevMarker = this.currentMarker;
|
|
this.currentMarker = null;
|
|
this.currentMarkerIdx = null;
|
|
|
|
for (var i = 0; i < this.markers.length; ++i) {
|
|
var marker = this.markers[i];
|
|
if (marker.timestamp <= this.currentTime && this.currentTime < marker.endTime) {
|
|
this.currentMarker = marker;
|
|
this.currentMarkerIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (this.currentMarker) {
|
|
var CineraContent = this.currentMarker.el.querySelector(".cineraContent");
|
|
var totalWidth = CineraContent.offsetWidth;
|
|
var progress = (this.currentTime - this.currentMarker.timestamp) / (this.currentMarker.endTime - this.currentMarker.timestamp);
|
|
if (this.currentMarker.hoverx === null) {
|
|
var pixelWidth = progress * totalWidth;
|
|
this.currentMarker.fadedProgress.style.width = Math.ceil(pixelWidth) + "px";
|
|
this.currentMarker.fadedProgress.style.opacity = pixelWidth - Math.floor(pixelWidth);
|
|
this.currentMarker.progress.style.width = Math.floor(pixelWidth) + "px";
|
|
} else {
|
|
this.currentMarker.fadedProgress.style.opacity = 1;
|
|
this.currentMarker.progress.style.width = Math.floor(Math.min(this.currentMarker.hoverx, progress) * totalWidth) + "px";
|
|
this.currentMarker.fadedProgress.style.width = Math.floor(Math.max(this.currentMarker.hoverx, progress) * totalWidth) + "px";
|
|
}
|
|
|
|
}
|
|
|
|
if (this.currentMarker != prevMarker) {
|
|
if (prevMarker) {
|
|
prevMarker.el.classList.remove("current");
|
|
prevMarker.fadedProgress.style.width = "0px";
|
|
prevMarker.progress.style.width = "0px";
|
|
prevMarker.hoverx = null;
|
|
}
|
|
|
|
if (this.currentMarker) {
|
|
if(this.currentMarkerIdx == this.markers.length - 1)
|
|
{
|
|
localStorage.removeItem(this.lastTimestampStorageItem);
|
|
}
|
|
else
|
|
{
|
|
localStorage.setItem(this.lastTimestampStorageItem, this.currentMarker.timestamp);
|
|
}
|
|
this.currentMarker.el.classList.add("current");
|
|
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.currentMarker.el, true, true);
|
|
this.refsCallback(this.currentMarker.ref, this.currentMarker.el, this);
|
|
} else if (prevMarker && prevMarker.ref) {
|
|
this.refsCallback(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
Player.prototype.smoothScroll = function(MenuEntity)
|
|
{
|
|
var container = MenuEntity.Container;
|
|
var scroller = MenuEntity.Scroll;
|
|
var targetPosition = scroller.To;
|
|
targetPosition = Math.max(0, Math.min(targetPosition, container.scrollHeight - container.offsetHeight));
|
|
scroller.Position += (targetPosition - scroller.Position) * 0.1;
|
|
if (Math.abs(scroller.Position - targetPosition) < 1.0) {
|
|
container.scrollTop = targetPosition;
|
|
scroller.To = -1;
|
|
} else {
|
|
container.scrollTop = scroller.Position;
|
|
}
|
|
}
|
|
|
|
Player.prototype.doFrame = function() {
|
|
if (this.playing) {
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
this.currentTime = this.platformPlayer.currentTime;
|
|
if(this.desiredTime == -1) { this.desiredTime = this.currentTime; }
|
|
this.updateProgress();
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
var Parent = this;
|
|
this.platformPlayer.getCurrentTime()
|
|
.then(function(Result) {
|
|
Parent.currentTime = Result;
|
|
if(Parent.desiredTime == -1) { Parent.desiredTime = Parent.currentTime; }
|
|
Parent.updateProgress();
|
|
});
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
this.currentTime = this.platformPlayer.getCurrentTime();
|
|
if(this.desiredTime == -1) { this.desiredTime = this.currentTime; }
|
|
this.updateProgress();
|
|
} break;
|
|
}
|
|
}
|
|
|
|
if (this.Menus[menu_id.MARKERS].Scroll.To >= 0) {
|
|
this.smoothScroll(this.Menus[menu_id.MARKERS]);
|
|
}
|
|
|
|
if(this.Menus[menu_id.QUOTES].Container && this.Menus[menu_id.QUOTES].Scroll.To >= 0) {
|
|
this.smoothScroll(this.Menus[menu_id.QUOTES]);
|
|
}
|
|
|
|
if(this.Menus[menu_id.REFERENCES].Container && this.Menus[menu_id.REFERENCES].Scroll.To >= 0) {
|
|
this.smoothScroll(this.Menus[menu_id.REFERENCES]);
|
|
}
|
|
|
|
if(this.Menus[menu_id.FILTER].Container && this.Menus[menu_id.FILTER].Scroll.To >= 0) {
|
|
this.smoothScroll(this.Menus[menu_id.FILTER]);
|
|
}
|
|
|
|
if(this.Menus[menu_id.CREDITS].Container && this.Menus[menu_id.CREDITS].Scroll.To >= 0) {
|
|
this.smoothScroll(this.Menus[menu_id.CREDITS]);
|
|
}
|
|
|
|
if(this.desiredTime == this.currentTime) { this.desiredTime = -1; }
|
|
|
|
this.nextFrame = requestAnimationFrame(this.doFrame.bind(this));
|
|
this.updateLink();
|
|
};
|
|
|
|
Player.prototype.setStyleAndQuality = function() {
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
// NOTE(matt): onPlatformReady() has set the width and height
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
this.platformPlayer.setQuality("1080p");
|
|
var frame = this.videoContainer.querySelector("iframe");
|
|
frame.style.width = "100%";
|
|
frame.style.height = "100%";
|
|
frame.style.position = "absolute"
|
|
frame.style.top = 0;
|
|
frame.style.left = 0;
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
this.platformPlayer.setPlaybackQuality("hd1080");
|
|
} break;
|
|
}
|
|
this.updateSize();
|
|
}
|
|
|
|
Player.prototype.setDurationThenAutoplay = function(Duration) {
|
|
this.duration = Duration;
|
|
this.markers[this.markers.length-1].endTime = this.duration;
|
|
if (this.desiredTime > 0) {
|
|
this.desiredTime = Math.max(0, Math.min(this.desiredTime, this.duration));
|
|
this.setTimeThenPlay(this.desiredTime);
|
|
}
|
|
if (this.shouldPlay) {
|
|
this.play();
|
|
}
|
|
}
|
|
|
|
Player.prototype.acquireDurationThenAutoplay = function() {
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
this.setDurationThenAutoplay(this.platformPlayer.duration);
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
var Parent = this;
|
|
this.platformPlayer.getDuration()
|
|
.then(function(Response)
|
|
{
|
|
Parent.setDurationThenAutoplay(Response);
|
|
});
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
this.setDurationThenAutoplay(this.platformPlayer.getDuration());
|
|
} break;
|
|
}
|
|
}
|
|
|
|
Player.prototype.onPlatformPlayerReady = function() {
|
|
this.platformPlayerReady = true;
|
|
this.setStyleAndQuality();
|
|
this.acquireDurationThenAutoplay();
|
|
};
|
|
|
|
Player.prototype.onPlaybackRateChange = function(Rate)
|
|
{
|
|
this.speed = Rate;
|
|
}
|
|
|
|
Player.prototype.onDirectPlayerPlaybackRateChange = function(ev) {
|
|
this.onPlaybackRateChange(this.platformPlayer.playbackRate);
|
|
};
|
|
|
|
Player.prototype.onVimeoPlayerPlaybackRateChange = function(ev) {
|
|
this.onPlaybackRateChange(ev.playbackRate);
|
|
};
|
|
|
|
Player.prototype.onYouTubePlayerPlaybackRateChange = function(ev) {
|
|
this.onPlaybackRateChange(ev.data);
|
|
};
|
|
|
|
Player.prototype.onStateBufferStart = function()
|
|
{
|
|
this.buffering = true;
|
|
this.updateProgress();
|
|
}
|
|
|
|
Player.prototype.onStateBufferEnd = function()
|
|
{
|
|
this.buffering = false;
|
|
this.updateProgress();
|
|
}
|
|
|
|
Player.prototype.onStateEnded = function()
|
|
{
|
|
this.buffering = false;
|
|
this.playing = false;
|
|
localStorage.removeItem(this.lastTimestampStorageItem);
|
|
this.currentTime = null;
|
|
this.updateProgress();
|
|
}
|
|
|
|
Player.prototype.onStatePaused = function(CurrentTime)
|
|
{
|
|
this.buffering = false;
|
|
this.playing = false;
|
|
this.currentTime = CurrentTime;
|
|
this.updateProgress();
|
|
}
|
|
|
|
Player.prototype.onStatePlaying = function(CurrentTime)
|
|
{
|
|
this.buffering = false;
|
|
this.playing = true;
|
|
this.currentTime = CurrentTime;
|
|
if(this.pauseAfterBuffer)
|
|
{
|
|
this.pauseAfterBuffer = false;
|
|
this.pause();
|
|
}
|
|
}
|
|
|
|
Player.prototype.onDirectPlayerStateChange_Paused = function(ev)
|
|
{
|
|
this.onStatePaused(this.platformPlayer.currentTime);
|
|
}
|
|
|
|
Player.prototype.onDirectPlayerStateChange_Playing = function(ev)
|
|
{
|
|
this.onStatePlaying(this.platformPlayer.currentTime);
|
|
}
|
|
|
|
Player.prototype.onVimeoPlayerStateChange_Paused = function(ev)
|
|
{
|
|
this.onStatePaused(ev.seconds);
|
|
}
|
|
|
|
Player.prototype.onVimeoPlayerStateChange_Playing = function(ev)
|
|
{
|
|
this.onStatePlaying(ev.seconds);
|
|
}
|
|
|
|
Player.prototype.onYouTubePlayerStateChange = function(ev) {
|
|
switch(ev.data)
|
|
{
|
|
case YT.PlayerState.BUFFERING: { this.onStateBufferStart(); }; break;
|
|
case YT.PlayerState.ENDED: { this.onStateEnded(); }; break;
|
|
case YT.PlayerState.PAUSED: { this.onStatePaused(this.platformPlayer.getCurrentTime()); }; break;
|
|
case YT.PlayerState.PLAYING: { this.onStatePlaying(this.platformPlayer.getCurrentTime()); }; break;
|
|
default: break;
|
|
}
|
|
};
|
|
|
|
Player.prototype.onPlatformReady = function() {
|
|
var platformPlayerDiv = document.createElement("DIV");
|
|
platformPlayerDiv.id = "platform_player_" + Player.platformPlayerCount++;
|
|
var platformPlayerDivPlaced = this.videoContainer.appendChild(platformPlayerDiv);
|
|
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
platformPlayerDivPlaced.classList.add("direct_video");
|
|
var videoNode = document.createElement("VIDEO");
|
|
videoNode.controls = true;
|
|
videoNode.setAttribute("width", this.videoContainer.offsetWidth);
|
|
videoNode.setAttribute("height", this.videoContainer.offsetWidth / 16 * 9);
|
|
var videoSourceNode = document.createElement("SOURCE");
|
|
videoSourceNode.setAttribute("src", this.videoContainer.getAttribute("data-videoId"));
|
|
videoNode.appendChild(videoSourceNode);
|
|
this.platformPlayer = platformPlayerDiv.appendChild(videoNode);
|
|
this.platformPlayer.addEventListener("loadedmetadata", this.onPlatformPlayerReady.bind(this));
|
|
this.platformPlayer.addEventListener("ratechange", this.onDirectPlayerPlaybackRateChange.bind(this));
|
|
this.platformPlayer.addEventListener("play", this.onDirectPlayerStateChange_Playing.bind(this));
|
|
this.platformPlayer.addEventListener("pause", this.onDirectPlayerStateChange_Paused.bind(this));
|
|
this.platformPlayer.addEventListener("waiting", this.onStateBufferStart.bind(this));
|
|
this.platformPlayer.addEventListener("playing", this.onStateBufferEnd.bind(this));
|
|
this.platformPlayer.addEventListener("ended", this.onStateEnded.bind(this));
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
this.videoContainer.style.position = "relative";
|
|
if(!CineraProps.IsMobile)
|
|
{
|
|
this.videoContainer.style.alignSelf = "unset";
|
|
}
|
|
|
|
var CallData = {
|
|
id: this.videoContainer.getAttribute("data-videoId"),
|
|
title: false,
|
|
};
|
|
var CCLang = this.videoContainer.getAttribute("data-ccLang");
|
|
if(CCLang != null)
|
|
{
|
|
CallData.texttrack = CCLang;
|
|
}
|
|
|
|
this.platformPlayer = new Vimeo.Player(platformPlayerDiv.id, CallData);
|
|
|
|
this.platformPlayer.ready()
|
|
.then(this.onPlatformPlayerReady.bind(this));
|
|
this.platformPlayer.on("playbackratechange", this.onVimeoPlayerPlaybackRateChange.bind(this));
|
|
this.platformPlayer.on("play", this.onVimeoPlayerStateChange_Playing.bind(this));
|
|
this.platformPlayer.on("pause", this.onVimeoPlayerStateChange_Paused.bind(this));
|
|
this.platformPlayer.on("bufferstart", this.onStateBufferStart.bind());
|
|
this.platformPlayer.on("bufferend", this.onStateBufferEnd.bind());
|
|
this.platformPlayer.on("ended", this.onStateEnded.bind());
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
var CallData = {
|
|
videoId: this.videoContainer.getAttribute("data-videoId"),
|
|
width: this.videoContainer.offsetWidth,
|
|
height: this.videoContainer.offsetWidth / 16 * 9,
|
|
playerVars: { 'playsinline': 1 },
|
|
events: {
|
|
"onReady": this.onPlatformPlayerReady.bind(this),
|
|
"onStateChange": this.onYouTubePlayerStateChange.bind(this),
|
|
"onPlaybackRateChange": this.onYouTubePlayerPlaybackRateChange.bind(this)
|
|
}
|
|
};
|
|
var CCLang = this.videoContainer.getAttribute("data-ccLang");
|
|
if(CCLang != null)
|
|
{
|
|
CallData.cc_lang_pref = CCLang;
|
|
CallData.cc_load_policy = 1;
|
|
}
|
|
|
|
this.platformPlayer = new YT.Player(platformPlayerDiv.id, CallData);
|
|
} break;
|
|
}
|
|
};
|
|
|
|
Player.platformPlayerCount = 0;
|
|
|
|
Player.prototype.toggleFilterMode = function() {
|
|
if(this.filterMode == "inclusive")
|
|
{
|
|
this.filterModeElement.classList.remove("inclusive");
|
|
this.filterModeElement.classList.add("exclusive");
|
|
this.filterMode = "exclusive";
|
|
}
|
|
else
|
|
{
|
|
this.filterModeElement.classList.remove("exclusive");
|
|
this.filterModeElement.classList.add("inclusive");
|
|
this.filterMode = "inclusive";
|
|
}
|
|
this.applyFilter();
|
|
}
|
|
|
|
Player.prototype.updateLink = function()
|
|
{
|
|
if(this.link)
|
|
{
|
|
if(this.linkTimestamp == true)
|
|
{
|
|
if(this.currentMarker)
|
|
{
|
|
this.link.value = baseURL + "#" + this.currentMarker.timestamp;
|
|
}
|
|
else
|
|
{
|
|
this.link.value = baseURL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(this.vod_platform)
|
|
{
|
|
case vod_platform.DIRECT:
|
|
{
|
|
this.link.value = baseURL + "#" + Math.round(this.platformPlayer.currentTime);
|
|
} break;
|
|
case vod_platform.VIMEO:
|
|
{
|
|
var Parent = this;
|
|
this.platformPlayer.getCurrentTime()
|
|
.then(function(Response)
|
|
{
|
|
Parent.link.value = baseURL + "#" + Math.round(Response);
|
|
});
|
|
} break;
|
|
case vod_platform.YOUTUBE:
|
|
{
|
|
this.link.value = baseURL + "#" + Math.round(this.platformPlayer.getCurrentTime());
|
|
} break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Player.prototype.toggleLinkMode = function()
|
|
{
|
|
this.linkTimestamp = !this.linkTimestamp;
|
|
if(this.linkTimestamp == true)
|
|
{
|
|
this.linkMode.textContent = "Link to: current timestamp";
|
|
}
|
|
else
|
|
{
|
|
this.linkMode.textContent = "Link to: nearest second";
|
|
}
|
|
this.updateLink();
|
|
}
|
|
|
|
Player.prototype.toggleFilterOrLinkMode = function()
|
|
{
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.FILTER:
|
|
{
|
|
this.toggleFilterMode();
|
|
} break;
|
|
case menu_id.LINK:
|
|
{
|
|
this.toggleLinkMode();
|
|
} break;
|
|
}
|
|
}
|
|
|
|
function HideMenu(MenuContainer)
|
|
{
|
|
if(MenuContainer != null)
|
|
{
|
|
MenuContainer.classList.remove("visible");
|
|
MenuContainer.parentNode.classList.remove("visible");
|
|
}
|
|
}
|
|
|
|
function ShowMenu(MenuContainer)
|
|
{
|
|
if(MenuContainer != null)
|
|
{
|
|
MenuContainer.classList.add("visible");
|
|
MenuContainer.parentNode.classList.add("visible");
|
|
}
|
|
}
|
|
|
|
Player.prototype.toggleMenuVisibility = function(MenuID, Trigger) {
|
|
var element = this.Menus[MenuID].Container;
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
this.unfocusUIElement(focus_level.ITEM);
|
|
}
|
|
if(this.MenusFocused.Identifier)
|
|
{
|
|
this.unfocusUIElement(focus_level.IDENTIFIER);
|
|
}
|
|
|
|
if(element.classList.contains("visible"))
|
|
{
|
|
HideMenu(element);
|
|
|
|
if(Trigger == trigger_id.KEYBOARD && this.Menus[menu_id.MARKERS].Item.LastFocused)
|
|
{
|
|
var Best = this.Menus[menu_id.MARKERS].Item.LastFocused;
|
|
while(Best.classList.contains("skip") && Best.nextElementSibling)
|
|
{
|
|
Best = Best.nextElementSibling;
|
|
}
|
|
|
|
if(!Best.classList.contains("skip"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.MARKERS, this.Menus[menu_id.MARKERS].Item, Best);
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.MenusFocused.Item, true, false);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.MenusFocused.MenuID = MenuID;
|
|
for(var i in this.Menus)
|
|
{
|
|
HideMenu(this.Menus[i].Container);
|
|
}
|
|
ShowMenu(element);
|
|
|
|
switch(MenuID)
|
|
{
|
|
case menu_id.QUOTES:
|
|
{
|
|
if(!this.Menus[menu_id.QUOTES].Item.LastFocused || !this.Menus[menu_id.QUOTES].Identifier.LastFocused)
|
|
{
|
|
this.Menus[menu_id.QUOTES].Item.LastFocused = element.querySelector(".ref");
|
|
this.Menus[menu_id.QUOTES].Identifier.LastFocused = this.Menus[menu_id.QUOTES].Item.LastFocused.querySelector(".ref_indices").firstElementChild;
|
|
}
|
|
this.focusUIElement(focus_level.ITEM, menu_id.QUOTES, this.Menus[menu_id.QUOTES].Item, this.Menus[menu_id.QUOTES].Item.LastFocused);
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.QUOTES, this.Menus[menu_id.QUOTES].Identifier, this.Menus[menu_id.QUOTES].Identifier.LastFocused);
|
|
} break;
|
|
case menu_id.REFERENCES:
|
|
{
|
|
if(!this.Menus[menu_id.REFERENCES].Item.LastFocused || !this.Menus[menu_id.REFERENCES].Identifier.LastFocused)
|
|
{
|
|
this.Menus[menu_id.REFERENCES].Item.LastFocused = element.querySelector(".ref");
|
|
this.Menus[menu_id.REFERENCES].Identifier.LastFocused = this.Menus[menu_id.REFERENCES].Item.LastFocused.querySelector(".ref_indices").firstElementChild;
|
|
}
|
|
this.focusUIElement(focus_level.ITEM, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Item, this.Menus[menu_id.REFERENCES].Item.LastFocused);
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Identifier, this.Menus[menu_id.REFERENCES].Identifier.LastFocused);
|
|
} break;
|
|
case menu_id.FILTER:
|
|
{
|
|
if(!this.Menus[menu_id.FILTER].Category.LastFocused)
|
|
{
|
|
this.Menus[menu_id.FILTER].Category.LastFocused = element.querySelector(".filter_content");
|
|
}
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, this.Menus[menu_id.FILTER].Category.LastFocused);
|
|
} break;
|
|
case menu_id.CREDITS:
|
|
{
|
|
if(!this.Menus[menu_id.CREDITS].Item.LastFocused)
|
|
{
|
|
if(element.querySelector(".credit .person").nextElementSibling)
|
|
{
|
|
this.Menus[menu_id.CREDITS].Item.LastFocused = element.querySelector(".credit .support");
|
|
}
|
|
else
|
|
{
|
|
this.Menus[menu_id.CREDITS].Item.LastFocused = element.querySelector(".credit .person");
|
|
}
|
|
}
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, this.Menus[menu_id.CREDITS].Item.LastFocused);
|
|
} break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Player.prototype.handleMouseOverViewsMenu = function()
|
|
{
|
|
switch(CineraProps.V)
|
|
{
|
|
case views.REGULAR:
|
|
case views.THEATRE:
|
|
{
|
|
this.Menus[menu_id.VIEWS].Container.classList.add("visible");
|
|
} break;
|
|
case views.SUPERTHEATRE:
|
|
{
|
|
} break;
|
|
}
|
|
this.MenusFocused.MenuID = menu_id.VIEWS;
|
|
}
|
|
|
|
function IsFullScreen()
|
|
{
|
|
return (document.fullscreen || document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement || document.fullscreenElement);
|
|
}
|
|
|
|
function enterFullScreen_()
|
|
{
|
|
if(!IsFullScreen())
|
|
{
|
|
if(document.body.requestFullscreen) { document.body.requestFullscreen(); }
|
|
else if(document.body.mozRequestFullScreen) { document.body.mozRequestFullScreen(); }
|
|
else if(document.body.webkitRequestFullScreen) { document.body.webkitRequestFullScreen(); }
|
|
else if(document.body.msRequestFullscreen) { document.body.msRequestFullscreen(); }
|
|
}
|
|
}
|
|
|
|
function leaveFullScreen_()
|
|
{
|
|
if(IsFullScreen())
|
|
{
|
|
if(document.exitFullscreen) { document.exitFullscreen(); }
|
|
else if(document.mozCancelFullScreen) { document.mozCancelFullScreen(); }
|
|
else if(document.webkitCancelFullScreen) { document.webkitCancelFullScreen(); }
|
|
else if(document.msExitFullscreen) { document.msExitFullscreen(); }
|
|
}
|
|
}
|
|
|
|
Player.prototype.toggleTheatreMode = function() {
|
|
if(!CineraProps.IsMobile)
|
|
{
|
|
switch(CineraProps.V)
|
|
{
|
|
case views.REGULAR:
|
|
{
|
|
CineraProps.C = this.root.style.backgroundColor;
|
|
CineraProps.Z = this.root.style.zIndex;
|
|
CineraProps.X = this.root.style.left;
|
|
CineraProps.Y = this.root.style.top;
|
|
CineraProps.W = this.root.style.width;
|
|
CineraProps.mW = this.root.style.maxWidth;
|
|
CineraProps.H = this.root.style.height;
|
|
CineraProps.mH = this.root.style.maxHeight;
|
|
CineraProps.P = this.root.style.position;
|
|
CineraProps.Display = this.root.style.display;
|
|
CineraProps.FlexDirection = this.root.style.flexDirection;
|
|
CineraProps.JustifyContent = this.root.style.justifyContent;
|
|
CineraProps.ScrollX = window.scrollX;
|
|
CineraProps.ScrollY = window.scrollY;
|
|
|
|
this.root.style.backgroundColor = "#000";
|
|
this.root.style.zIndex = 64;
|
|
this.root.style.left = 0;
|
|
this.root.style.top = 0;
|
|
this.root.style.width = "100%";
|
|
this.root.style.maxWidth = "100%";
|
|
this.root.style.height = "100%";
|
|
this.root.style.maxHeight = "100%";
|
|
this.root.style.position = "fixed";
|
|
this.root.style.display = "flex";
|
|
this.root.style.flexDirection = "column";
|
|
this.root.style.justifyContent = "center";
|
|
|
|
this.viewItems[0].setAttribute("data-id", "regular");
|
|
this.viewItems[0].setAttribute("title", "Regular mode");
|
|
this.viewItems[0].firstChild.nodeValue = "📺";
|
|
} CineraProps.V = views.THEATRE; localStorage.setItem(this.cineraViewStorageItem, views.THEATRE); break;
|
|
case views.SUPERTHEATRE:
|
|
{
|
|
leaveFullScreen_();
|
|
}
|
|
case views.THEATRE:
|
|
{
|
|
this.root.style.backgroundColor = CineraProps.C;
|
|
this.root.style.zIndex = CineraProps.Z;
|
|
this.root.style.left = CineraProps.X;
|
|
this.root.style.top = CineraProps.Y;
|
|
this.root.style.width = CineraProps.W;
|
|
this.root.style.maxWidth = CineraProps.mW;
|
|
this.root.style.height = CineraProps.H;
|
|
this.root.style.maxHeight = CineraProps.mH;
|
|
this.root.style.position = CineraProps.P;
|
|
this.root.style.display = CineraProps.Display;
|
|
this.root.style.flexDirection = CineraProps.FlexDirection;
|
|
this.root.style.justifyContent = CineraProps.JustifyContent;
|
|
window.scroll(
|
|
{
|
|
top: CineraProps.ScrollY,
|
|
left: CineraProps.ScrollX
|
|
}
|
|
);
|
|
|
|
this.viewItems[0].setAttribute("data-id", "theatre");
|
|
this.viewItems[0].setAttribute("title", "Theatre mode");
|
|
this.viewItems[0].firstChild.nodeValue = "🎭";
|
|
} CineraProps.V = views.REGULAR; localStorage.removeItem(this.cineraViewStorageItem); break;
|
|
}
|
|
this.updateSize();
|
|
}
|
|
}
|
|
|
|
Player.prototype.toggleSuperTheatreMode = function()
|
|
{
|
|
if(!CineraProps.IsMobile)
|
|
{
|
|
switch(CineraProps.V)
|
|
{
|
|
case views.REGULAR:
|
|
{
|
|
this.toggleTheatreMode();
|
|
}
|
|
case views.THEATRE:
|
|
{
|
|
enterFullScreen_();
|
|
} CineraProps.V = views.SUPERTHEATRE; localStorage.setItem(this.cineraViewStorageItem, views.SUPERTHEATRE); break;
|
|
case views.SUPERTHEATRE:
|
|
{
|
|
leaveFullScreen_();
|
|
this.toggleTheatreMode();
|
|
} CineraProps.V = views.REGULAR; localStorage.removeItem(this.cineraViewStorageItem); break;
|
|
}
|
|
this.updateSize();
|
|
}
|
|
}
|
|
|
|
function AscribeTemporaryResponsibility(Element, Milliseconds)
|
|
{
|
|
if(!Element.classList.contains("responsible"))
|
|
{
|
|
Element.classList.add("responsible");
|
|
}
|
|
setTimeout(function() { Element.classList.remove("responsible"); }, Milliseconds);
|
|
}
|
|
|
|
function SelectText(inputElement)
|
|
{
|
|
inputElement.select();
|
|
}
|
|
|
|
Player.prototype.CopyToClipboard = function(inputElement)
|
|
{
|
|
SelectText(inputElement);
|
|
document.execCommand("copy");
|
|
AscribeTemporaryResponsibility(this.Menus[menu_id.LINK].Container.parentNode, 8000);
|
|
}
|
|
|
|
Player.prototype.unfocusUIElement = function(FocusLevel)
|
|
{
|
|
switch(FocusLevel)
|
|
{
|
|
case focus_level.ITEM:
|
|
{
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
this.MenusFocused.Item.classList.remove("focused");
|
|
unfocusSprite(this.MenusFocused.Item);
|
|
}
|
|
this.MenusFocused.Item = null;
|
|
} break;
|
|
case focus_level.IDENTIFIER:
|
|
{
|
|
if(this.MenusFocused.Identifier)
|
|
{
|
|
this.MenusFocused.Identifier.classList.remove("focused");
|
|
unfocusSprite(this.MenusFocused.Identifier);
|
|
}
|
|
this.MenusFocused.Identifier = null;
|
|
} break;
|
|
}
|
|
this.MenusFocused.MenuID = menu_id.UNSET;
|
|
}
|
|
|
|
Player.prototype.focusUIElement = function(FocusLevel, MenuID, MenuFocalPoint, newElement)
|
|
{
|
|
switch(FocusLevel)
|
|
{
|
|
case focus_level.ITEM:
|
|
{
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
this.MenusFocused.Item.classList.remove("focused");
|
|
unfocusSprite(this.MenusFocused.Item);
|
|
}
|
|
this.MenusFocused.Item = newElement;
|
|
} break;
|
|
case focus_level.IDENTIFIER:
|
|
{
|
|
if(this.MenusFocused.Identifier)
|
|
{
|
|
this.MenusFocused.Identifier.classList.remove("focused");
|
|
unfocusSprite(this.MenusFocused.Identifier);
|
|
}
|
|
this.MenusFocused.Identifier = newElement;
|
|
} break;
|
|
}
|
|
this.MenusFocused.MenuID = MenuID;
|
|
|
|
newElement.classList.add("focused");
|
|
focusSprite(newElement);
|
|
MenuFocalPoint.LastFocused = newElement;
|
|
}
|
|
|
|
function
|
|
getMostRecentCitation(currentTime, citations)
|
|
{
|
|
var Result = citations[0];
|
|
for(var i = 0; i < citations.length; ++i)
|
|
{
|
|
var citation = citations[i];
|
|
if(citation.getAttribute("data-timestamp") <= currentTime)
|
|
{
|
|
Result = citation;
|
|
}
|
|
else { break; }
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
Player.prototype.handleKey = function(key) {
|
|
var gotKey = true;
|
|
switch (key) {
|
|
case "Escape": {
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.MARKERS:
|
|
{
|
|
this.unfocusUIElement(focus_level.ITEM);
|
|
if(this.currentMarker && this.currentMarker.el)
|
|
{
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.currentMarker.el, true, false);
|
|
}
|
|
this.Menus[menu_id.MARKERS].Item.LastFocused = null;
|
|
} break;
|
|
case menu_id.QUOTES:
|
|
case menu_id.REFERENCES:
|
|
case menu_id.FILTER:
|
|
case menu_id.VIEWS:
|
|
case menu_id.LINK:
|
|
case menu_id.CREDITS:
|
|
{
|
|
this.toggleMenuVisibility(this.MenusFocused.MenuID, trigger_id.KEYBOARD);
|
|
} break;
|
|
}
|
|
} break;
|
|
case "q": {
|
|
if(this.Menus[menu_id.QUOTES].Container)
|
|
{
|
|
this.toggleMenuVisibility(menu_id.QUOTES, trigger_id.KEYBOARD);
|
|
}
|
|
} break;
|
|
case "r": {
|
|
if(this.Menus[menu_id.REFERENCES].Container)
|
|
{
|
|
this.toggleMenuVisibility(menu_id.REFERENCES, trigger_id.KEYBOARD);
|
|
}
|
|
} break;
|
|
case "f": {
|
|
if(this.Menus[menu_id.FILTER].Container)
|
|
{
|
|
this.toggleMenuVisibility(menu_id.FILTER, trigger_id.KEYBOARD);
|
|
}
|
|
} break;
|
|
case "y": {
|
|
if(this.Menus[menu_id.LINK].Container)
|
|
{
|
|
this.toggleMenuVisibility(menu_id.LINK, trigger_id.KEYBOARD);
|
|
}
|
|
break;
|
|
}
|
|
case "c": {
|
|
if(this.Menus[menu_id.CREDITS].Container)
|
|
{
|
|
this.toggleMenuVisibility(menu_id.CREDITS, trigger_id.KEYBOARD);
|
|
}
|
|
} break;
|
|
case "t": {
|
|
if(this.root)
|
|
{
|
|
this.toggleTheatreMode();
|
|
}
|
|
} break;
|
|
case "T": {
|
|
if(this.root)
|
|
{
|
|
this.toggleSuperTheatreMode();
|
|
}
|
|
} break;
|
|
|
|
case "Enter": {
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.MARKERS:
|
|
{
|
|
var time = this.MenusFocused.Item.getAttribute("data-timestamp");
|
|
this.setTimeThenPlay(parseFloat(time));
|
|
} break;
|
|
case menu_id.QUOTES:
|
|
{
|
|
var time = this.MenusFocused.Item.querySelector(".timecode").getAttribute("data-timestamp");
|
|
this.setTimeThenPlay(parseFloat(time));
|
|
if(this.currentMarker)
|
|
{
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.currentMarker.el, true, false);
|
|
}
|
|
this.Menus[menu_id.MARKERS].Item.LastFocused = null;
|
|
} break;
|
|
case menu_id.REFERENCES:
|
|
{
|
|
var time = this.MenusFocused.Identifier.getAttribute("data-timestamp");
|
|
this.setTimeThenPlay(parseFloat(time));
|
|
if(this.currentMarker)
|
|
{
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.currentMarker.el, true, false);
|
|
}
|
|
this.Menus[menu_id.MARKERS].Item.LastFocused = null;
|
|
} break;
|
|
case menu_id.CREDITS:
|
|
{
|
|
if(this.MenusFocused.Item.hasAttribute)
|
|
{
|
|
var url = this.MenusFocused.Item.getAttribute("href");
|
|
if(url) { window.open(url, "_blank"); }
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(this.currentMarker && this.currentMarker.el)
|
|
{
|
|
var time = this.currentMarker.el.getAttribute("data-timestamp");
|
|
this.setTimeThenPlay(parseFloat(time));
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.currentMarker.el, true, false);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "o": {
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.REFERENCES:
|
|
case menu_id.QUOTES:
|
|
{
|
|
this.pause();
|
|
var url = this.MenusFocused.Item.getAttribute("href");
|
|
window.open(url, "_blank");
|
|
} break;
|
|
case menu_id.CREDITS:
|
|
{
|
|
if(this.MenusFocused.Item.hasAttribute("href"))
|
|
{
|
|
this.pause();
|
|
var url = this.MenusFocused.Item.getAttribute("href");
|
|
window.open(url, "_blank");
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "w": case "k": case "ArrowUp": {
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.MARKERS:
|
|
{
|
|
if(key != "ArrowUp")
|
|
{
|
|
if(this.MenusFocused.Item.previousElementSibling)
|
|
{
|
|
var Best = this.MenusFocused.Item.previousElementSibling;
|
|
while(Best.classList.contains("skip") && Best.previousElementSibling)
|
|
{
|
|
Best = Best.previousElementSibling;
|
|
}
|
|
|
|
if(!Best.classList.contains("skip"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.MARKERS, this.Menus[menu_id.MARKERS].Item, Best);
|
|
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.MenusFocused.Item, true, false);
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
case menu_id.QUOTES:
|
|
{
|
|
if(this.MenusFocused.Item.previousElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.QUOTES, this.Menus[menu_id.QUOTES].Item, this.MenusFocused.Item.previousElementSibling);
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.QUOTES, this.Menus[menu_id.QUOTES].Identifier, this.MenusFocused.Item.querySelector(".ref_indices").firstElementChild);
|
|
|
|
this.setScroller(this.Menus[menu_id.QUOTES], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.REFERENCES:
|
|
{
|
|
if(this.MenusFocused.Item.previousElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Item, this.MenusFocused.Item.previousElementSibling);
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Identifier, getMostRecentCitation(this.currentTime, this.MenusFocused.Item.querySelector(".ref_indices").children));
|
|
|
|
this.setScroller(this.Menus[menu_id.REFERENCES], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.FILTER:
|
|
{
|
|
if(this.MenusFocused.Item.previousElementSibling &&
|
|
this.MenusFocused.Item.previousElementSibling.classList.contains("filter_content"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, this.MenusFocused.Item.previousElementSibling);
|
|
|
|
this.setScroller(this.Menus[menu_id.FILTER], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.CREDITS:
|
|
{
|
|
if(this.MenusFocused.Item.parentNode.previousElementSibling)
|
|
{
|
|
if(this.MenusFocused.Item.parentNode.previousElementSibling.querySelector(".support") &&
|
|
this.MenusFocused.Item.classList.contains("support"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, this.MenusFocused.Item.parentNode.previousElementSibling.querySelector(".support"));
|
|
}
|
|
else
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, this.MenusFocused.Item.parentNode.previousElementSibling.querySelector(".person"));
|
|
}
|
|
|
|
this.setScroller(this.Menus[menu_id.CREDITS], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(key != "ArrowUp")
|
|
{
|
|
var Best;
|
|
if(this.currentMarker && this.currentMarker.el)
|
|
{
|
|
Best = this.currentMarker.el;
|
|
if(Best.previousElementSibling)
|
|
{
|
|
Best = Best.previousElementSibling;
|
|
while(Best.classList.contains("skip") && Best.previousElementSibling)
|
|
{
|
|
Best = Best.previousElementSibling;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Best = this.markers[0].el;
|
|
while(Best.classList.contains("skip") && Best.nextElementSibling)
|
|
{
|
|
Best = Best.nextElementSibling;
|
|
}
|
|
}
|
|
|
|
if(!Best.classList.contains("skip"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.MARKERS, this.Menus[menu_id.MARKERS].Item, Best);
|
|
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.MenusFocused.Item, true, false);
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "s": case "j": case "ArrowDown": {
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.MARKERS:
|
|
{
|
|
if(key != "ArrowDown")
|
|
{
|
|
if(this.MenusFocused.Item.nextElementSibling)
|
|
{
|
|
var Best = this.MenusFocused.Item.nextElementSibling;
|
|
while(Best.classList.contains("skip") && Best.nextElementSibling)
|
|
{
|
|
Best = Best.nextElementSibling;
|
|
}
|
|
|
|
if(!Best.classList.contains("skip"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.MARKERS, this.Menus[menu_id.MARKERS].Item, Best);
|
|
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.MenusFocused.Item, true, false);
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
case menu_id.QUOTES:
|
|
{
|
|
if(this.MenusFocused.Item.nextElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.QUOTES, this.Menus[menu_id.QUOTES].Item, this.MenusFocused.Item.nextElementSibling);
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.QUOTES, this.Menus[menu_id.QUOTES].Identifier, this.MenusFocused.Item.querySelector(".ref_indices").firstElementChild);
|
|
|
|
this.setScroller(this.Menus[menu_id.QUOTES], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.REFERENCES:
|
|
{
|
|
if(this.MenusFocused.Item.nextElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Item, this.MenusFocused.Item.nextElementSibling);
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Identifier, getMostRecentCitation(this.currentTime, this.MenusFocused.Item.querySelector(".ref_indices").children));
|
|
|
|
this.setScroller(this.Menus[menu_id.REFERENCES], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.FILTER:
|
|
{
|
|
if(this.MenusFocused.Item.nextElementSibling &&
|
|
this.MenusFocused.Item.nextElementSibling.classList.contains("filter_content"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, this.MenusFocused.Item.nextElementSibling);
|
|
|
|
this.setScroller(this.Menus[menu_id.FILTER], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.CREDITS:
|
|
{
|
|
if(this.MenusFocused.Item.parentNode.nextElementSibling)
|
|
{
|
|
if(this.MenusFocused.Item.parentNode.nextElementSibling.querySelector(".support") &&
|
|
this.MenusFocused.Item.classList.contains("support"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, this.MenusFocused.Item.parentNode.nextElementSibling.querySelector(".support"));
|
|
}
|
|
else
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, this.MenusFocused.Item.parentNode.nextElementSibling.querySelector(".person"));
|
|
}
|
|
|
|
this.setScroller(this.Menus[menu_id.CREDITS], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(key != "ArrowDown")
|
|
{
|
|
var Best;
|
|
if(this.currentMarker && this.currentMarker.el)
|
|
{
|
|
Best = this.currentMarker.el;
|
|
if(Best.nextElementSibling)
|
|
{
|
|
Best = Best.nextElementSibling;
|
|
while(Best.classList.contains("skip") && Best.nextElementSibling)
|
|
{
|
|
Best = Best.nextElementSibling;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Best = this.markers[0].el;
|
|
while(Best.classList.contains("skip") && Best.nextElementSibling)
|
|
{
|
|
Best = Best.nextElementSibling;
|
|
}
|
|
}
|
|
|
|
if(!Best.classList.contains("skip"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.MARKERS, this.Menus[menu_id.MARKERS].Item, Best);
|
|
|
|
this.setScroller(this.Menus[menu_id.MARKERS], this.MenusFocused.Item, true, false);
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "a": case "h": case "ArrowLeft": {
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.REFERENCES:
|
|
{
|
|
if(this.MenusFocused.Identifier.previousElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Identifier, this.MenusFocused.Identifier.previousElementSibling);
|
|
}
|
|
else if(this.MenusFocused.Identifier.parentNode.previousElementSibling.classList.contains("ref_indices"))
|
|
{
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Identifier, this.MenusFocused.Identifier.parentNode.previousElementSibling.lastElementChild);
|
|
}
|
|
} break;
|
|
case menu_id.FILTER:
|
|
{
|
|
if(this.MenusFocused.Item.parentNode.classList.contains("filter_media") &&
|
|
this.MenusFocused.Item.parentNode.previousElementSibling)
|
|
{
|
|
this.Menus[menu_id.FILTER].Medium.LastFocused = this.MenusFocused.Item;
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, this.Menus[menu_id.FILTER].Topic.LastFocused || this.MenusFocused.Item.parentNode.previousElementSibling.children[0]);
|
|
|
|
this.setScroller(this.Menus[menu_id.FILTER], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.CREDITS:
|
|
{
|
|
if(this.MenusFocused.Item.classList.contains("support"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, this.MenusFocused.Item.previousElementSibling);
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "d": case "l": case "ArrowRight": {
|
|
if(this.MenusFocused.Item)
|
|
{
|
|
switch(this.MenusFocused.MenuID)
|
|
{
|
|
case menu_id.REFERENCES:
|
|
{
|
|
if(this.MenusFocused.Identifier.nextElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Identifier, this.MenusFocused.Identifier.nextElementSibling);
|
|
}
|
|
else if(this.MenusFocused.Identifier.parentNode.nextElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.IDENTIFIER, menu_id.REFERENCES, this.Menus[menu_id.REFERENCES].Identifier, this.MenusFocused.Identifier.parentNode.nextElementSibling.firstElementChild);
|
|
}
|
|
} break;
|
|
case menu_id.FILTER:
|
|
{
|
|
if(this.MenusFocused.Item.parentNode.classList.contains("filter_topics") &&
|
|
this.MenusFocused.Item.parentNode.nextElementSibling)
|
|
{
|
|
this.Menus[menu_id.FILTER].Topic.LastFocused = this.MenusFocused.Item;
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, this.Menus[menu_id.FILTER].Medium.LastFocused || this.MenusFocused.Item.parentNode.nextElementSibling.children[0]);
|
|
|
|
this.setScroller(this.Menus[menu_id.FILTER], this.MenusFocused.Item, true, false);
|
|
}
|
|
} break;
|
|
case menu_id.CREDITS:
|
|
{
|
|
if(this.MenusFocused.Item.classList.contains("person") &&
|
|
this.MenusFocused.Item.nextElementSibling)
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, this.MenusFocused.Item.nextElementSibling);
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "x": case " ": {
|
|
if(this.MenusFocused.Item && this.MenusFocused.MenuID == menu_id.FILTER)
|
|
{
|
|
this.filterItemToggle(this.MenusFocused.Item);
|
|
if(this.MenusFocused.Item.nextElementSibling &&
|
|
this.MenusFocused.Item.nextElementSibling.classList.contains("filter_content"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, this.MenusFocused.Item.nextElementSibling);
|
|
|
|
this.setScroller(this.Menus[menu_id.FILTER], this.MenusFocused.Item, true, false);
|
|
if(this.MenusFocused.Item.parentNode.classList.contains("filter_topics"))
|
|
{
|
|
this.Menus[menu_id.FILTER].Topic.LastFocused = this.MenusFocused.Item;
|
|
}
|
|
else
|
|
{
|
|
this.Menus[menu_id.FILTER].Medium.LastFocused = this.MenusFocused.Item;
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "X": case "capitalSpace": {
|
|
if(this.MenusFocused.Item && this.MenusFocused.MenuID == menu_id.FILTER)
|
|
{
|
|
this.filterItemToggle(this.MenusFocused.Item);
|
|
if(this.MenusFocused.Item.previousElementSibling &&
|
|
this.MenusFocused.Item.previousElementSibling.classList.contains("filter_content"))
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, this.MenusFocused.Item.previousElementSibling);
|
|
|
|
this.setScroller(this.Menus[menu_id.FILTER], this.MenusFocused.Item, true, false);
|
|
if(this.MenusFocused.Item.parentNode.classList.contains("filter_topics"))
|
|
{
|
|
this.Menus[menu_id.FILTER].Topic.LastFocused = this.MenusFocused.Item;
|
|
}
|
|
else
|
|
{
|
|
this.Menus[menu_id.FILTER].Medium.LastFocused = this.MenusFocused.Item;
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case "z": {
|
|
this.toggleFilterOrLinkMode();
|
|
} break;
|
|
|
|
case "v": {
|
|
if(this.MenusFocused.Item && this.MenusFocused.MenuID == menu_id.FILTER)
|
|
{
|
|
this.invertFilter(this.MenusFocused.Item)
|
|
}
|
|
} break;
|
|
|
|
case "V": {
|
|
this.resetFilter();
|
|
} break;
|
|
|
|
case "?": {
|
|
if(this.helpDocumentation)
|
|
{
|
|
this.helpDocumentation.classList.toggle("visible");
|
|
}
|
|
} break;
|
|
|
|
case 'N':
|
|
case 'J':
|
|
case 'S': {
|
|
this.jumpToNextMarker();
|
|
} break;
|
|
|
|
case 'P':
|
|
case 'K':
|
|
case 'W': {
|
|
this.jumpToPrevMarker();
|
|
} break;
|
|
case '[':
|
|
case '<': {
|
|
if(this.prevEpisode)
|
|
{
|
|
location = this.prevEpisode.href;
|
|
}
|
|
} break;
|
|
case ']':
|
|
case '>': {
|
|
if(this.nextEpisode)
|
|
{
|
|
location = this.nextEpisode.href;
|
|
}
|
|
} break;
|
|
case 'Y': {
|
|
if(cineraLink)
|
|
{
|
|
if(this.linkTimestamp == false && this.playing)
|
|
{
|
|
this.pause();
|
|
}
|
|
if(this.Menus[menu_id.LINK].Container && !this.Menus[menu_id.LINK].Container.classList.contains("visible"))
|
|
{
|
|
this.toggleMenuVisibility(menu_id.LINK, trigger_id.KEYBOARD);
|
|
}
|
|
SelectText(cineraLink);
|
|
}
|
|
}
|
|
default: {
|
|
gotKey = false;
|
|
} break;
|
|
}
|
|
return gotKey;
|
|
}
|
|
|
|
Player.prototype.applyFilter = function() {
|
|
if(this.filterMode == "exclusive")
|
|
{
|
|
for(var i = 0; i < this.Menus[menu_id.MARKERS].Elements.length; ++i)
|
|
{
|
|
var Item = this.Menus[menu_id.MARKERS].Elements[i];
|
|
var testCategories = Item.classList;
|
|
for(var j = 0; j < testCategories.length; ++j)
|
|
{
|
|
if((testCategories[j].startsWith("off_")) && !Item.classList.contains("skip"))
|
|
{
|
|
Item.classList.add("skip");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(var i = 0; i < this.Menus[menu_id.MARKERS].Elements.length; ++i)
|
|
{
|
|
var Item = this.Menus[menu_id.MARKERS].Elements[i];
|
|
var testCategories = Item.classList;
|
|
for(var j = 0; j < testCategories.length; ++j)
|
|
{
|
|
var testCategory = testCategories[j];
|
|
if((testCategory in this.filterState || testCategory.startsWith("cat_")) && Item.classList.contains("skip"))
|
|
{
|
|
Item.classList.remove("skip");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Player.prototype.filterItemToggle = function(filterItem) {
|
|
var selectedCategory = filterItem.classList[1];
|
|
this.filterState[selectedCategory].off = !this.filterState[selectedCategory].off;
|
|
|
|
if(this.filterState[selectedCategory].off)
|
|
{
|
|
filterItem.classList.add("off");
|
|
disableSprite(filterItem);
|
|
if(!filterItem.parentNode.classList.contains("filter_media"))
|
|
{
|
|
filterItem.querySelector(".icon").style.backgroundColor = "transparent";
|
|
}
|
|
var testMarkers = this.Menus[menu_id.MARKERS].Container.querySelectorAll(".marker." + selectedCategory + ", .marker.cat_" + selectedCategory);
|
|
for(var i = 0; i < testMarkers.length; ++i)
|
|
{
|
|
var testMarker = testMarkers[i];
|
|
if(this.filterState[selectedCategory].type == "topic")
|
|
{
|
|
testMarker.classList.remove("cat_" + selectedCategory);
|
|
testMarker.classList.add("off_" + selectedCategory);
|
|
var markerCategories = testMarker.querySelectorAll(".category." + selectedCategory);
|
|
for(var j = 0; j < markerCategories.length; ++j)
|
|
{
|
|
var markerCategory = markerCategories[j];
|
|
if(markerCategory.classList.contains(selectedCategory))
|
|
{
|
|
markerCategory.classList.add("off");
|
|
markerCategory.style.backgroundColor = "transparent";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var markerCategories = testMarker.querySelectorAll(".categoryMedium." + selectedCategory);
|
|
for(var j = 0; j < markerCategories.length; ++j)
|
|
{
|
|
var markerCategory = markerCategories[j];
|
|
if(markerCategory.classList.contains(selectedCategory))
|
|
{
|
|
markerCategory.classList.add("off");
|
|
disableSprite(markerCategory);
|
|
}
|
|
}
|
|
testMarker.classList.remove(selectedCategory);
|
|
testMarker.classList.add("off_" + selectedCategory);
|
|
}
|
|
|
|
var Skipping = true;
|
|
if(this.filterMode == "exclusive")
|
|
{
|
|
testMarker.classList.add("skip");
|
|
}
|
|
else
|
|
{
|
|
var markerClasses = testMarker.classList;
|
|
for(var j = 0; j < markerClasses.length; ++j)
|
|
{
|
|
var markerClass = markerClasses[j];
|
|
if(markerClass in this.filterState || markerClass.replace(/^cat_/, "") in this.filterState)
|
|
{
|
|
Skipping = false;
|
|
}
|
|
}
|
|
if(Skipping)
|
|
{
|
|
testMarker.classList.add("skip");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
filterItem.classList.remove("off");
|
|
enableSprite(filterItem);
|
|
if(!filterItem.parentNode.classList.contains("filter_media"))
|
|
{
|
|
filterItem.querySelector(".icon").style.backgroundColor = getComputedStyle(filterItem.querySelector(".icon")).getPropertyValue("border-color");
|
|
}
|
|
setDotLightness(filterItem.querySelector(".icon"));
|
|
var testMarkers = this.Menus[menu_id.MARKERS].Container.querySelectorAll(".marker.off_" + selectedCategory);
|
|
for(var i = 0; i < testMarkers.length; ++i)
|
|
{
|
|
var testMarker = testMarkers[i];
|
|
if(this.filterState[selectedCategory].type == "topic")
|
|
{
|
|
testMarker.classList.remove("off_" + selectedCategory);
|
|
testMarker.classList.add("cat_" + selectedCategory);
|
|
var markerCategories = testMarker.querySelectorAll(".category." + selectedCategory);
|
|
for(var j = 0; j < markerCategories.length; ++j)
|
|
{
|
|
var markerCategory = markerCategories[j];
|
|
if(markerCategory.classList.contains(selectedCategory))
|
|
{
|
|
markerCategory.classList.remove("off");
|
|
markerCategory.style.backgroundColor = getComputedStyle(markerCategory).getPropertyValue("border-color");
|
|
setDotLightness(markerCategory);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
testMarker.classList.remove("off_" + selectedCategory);
|
|
testMarker.classList.add(selectedCategory);
|
|
var markerCategories = testMarker.querySelectorAll(".categoryMedium." + selectedCategory);
|
|
for(var j = 0; j < markerCategories.length; ++j)
|
|
{
|
|
var markerCategory = markerCategories[j];
|
|
if(markerCategory.classList.contains(selectedCategory))
|
|
{
|
|
markerCategory.classList.remove("off");
|
|
enableSprite(markerCategory);
|
|
}
|
|
}
|
|
}
|
|
|
|
var Skipping = false;
|
|
if(this.filterMode == "inclusive")
|
|
{
|
|
testMarker.classList.remove("skip");
|
|
}
|
|
else
|
|
{
|
|
var markerClasses = testMarker.classList;
|
|
for(var j = 0; j < markerClasses.length; ++j)
|
|
{
|
|
if(markerClasses[j].startsWith("off_"))
|
|
{
|
|
Skipping = true;
|
|
}
|
|
}
|
|
if(!Skipping)
|
|
{
|
|
testMarker.classList.remove("skip");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Player.prototype.resetFilter = function() {
|
|
for(var i in this.Menus[menu_id.FILTER].Elements)
|
|
{
|
|
var Item = this.Menus[menu_id.FILTER].Elements[i];
|
|
if(Item.classList)
|
|
{
|
|
var selectedCategory = Item.classList[1];
|
|
if(this.filterInitState[selectedCategory].off ^ this.filterState[selectedCategory].off)
|
|
{
|
|
this.filterItemToggle(Item);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(this.filterMode == "inclusive")
|
|
{
|
|
this.toggleFilterMode();
|
|
}
|
|
}
|
|
|
|
Player.prototype.invertFilter = function(FocusedElement) {
|
|
var siblings = player.MenusFocused.Item.parentNode.querySelectorAll(".filter_content");
|
|
for(var i in siblings)
|
|
{
|
|
var sibling = siblings[i];
|
|
if(sibling.classList)
|
|
{
|
|
this.filterItemToggle(sibling);
|
|
}
|
|
}
|
|
}
|
|
|
|
function resetFade(player) {
|
|
player.filter.classList.remove("responsible");
|
|
player.filter.querySelector(".filter_mode").classList.remove("responsible");
|
|
var responsibleCategories = player.filter.querySelectorAll(".filter_content.responsible");
|
|
for(var i = 0; i < responsibleCategories.length; ++i)
|
|
{
|
|
responsibleCategories[i].classList.remove("responsible");
|
|
}
|
|
}
|
|
|
|
Player.prototype.alignMenuWithTimestamp = function(ref, element, MenuID)
|
|
{
|
|
var MenuEntity = this.Menus[MenuID];
|
|
var Container = MenuEntity.Container;
|
|
if(Container)
|
|
{
|
|
var Toggler = Container.closest(".menu");
|
|
|
|
var SetMenu = 0;
|
|
if (ref !== undefined && ref !== null) {
|
|
var refs = ref.split(",");
|
|
|
|
var TargetTop = null;
|
|
var TargetBottom = null;
|
|
|
|
for (var i = 0; i < MenuEntity.Elements.length; ++i) {
|
|
var thisRef = MenuEntity.Elements[i];
|
|
if (refs.includes(thisRef.getAttribute("data-id"))) {
|
|
thisRef.classList.add("current");
|
|
if(!SetMenu)
|
|
{
|
|
if(this.MenusFocused.MenuID == MenuID)
|
|
{
|
|
this.focusUIElement(focus_level.ITEM, MenuID, MenuEntity.Item, thisRef);
|
|
}
|
|
else
|
|
{
|
|
MenuEntity.Item.LastFocused = thisRef;
|
|
}
|
|
|
|
TargetTop = thisRef;
|
|
|
|
var timecode = element.getAttribute("data-timestamp");
|
|
|
|
var ourIdentifiers = thisRef.querySelectorAll(".timecode");
|
|
for(var j = 0; j < ourIdentifiers.length; ++j)
|
|
{
|
|
var thisIdentifier = ourIdentifiers[j];
|
|
if(timecode == thisIdentifier.getAttribute("data-timestamp"))
|
|
{
|
|
if(this.MenusFocused.MenuID == MenuID)
|
|
{
|
|
this.focusUIElement(focus_level.IDENTIFIER, MenuID, MenuEntity.Identifier, thisIdentifier);
|
|
}
|
|
else
|
|
{
|
|
MenuEntity.Identifier.LastFocused = thisIdentifier;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
TargetBottom = thisRef;
|
|
SetMenu = 1;
|
|
} else {
|
|
thisRef.classList.remove("current");
|
|
}
|
|
}
|
|
if(SetMenu) {
|
|
Toggler.classList.add("current");
|
|
|
|
var CentreAlign = true;
|
|
if(!Container.classList.contains("visible"))
|
|
{
|
|
Container.scrollTop = this.computeDesiredScrollTo(MenuEntity, TargetTop, TargetBottom, CentreAlign);
|
|
}
|
|
else
|
|
{
|
|
this.setScrollerRanged(MenuEntity, TargetTop, TargetBottom, CentreAlign, true);
|
|
}
|
|
} else {
|
|
Toggler.classList.remove("current");
|
|
}
|
|
|
|
} else {
|
|
Toggler.classList.remove("current");
|
|
for (var i = 0; i < MenuEntity.Elements.length; ++i) {
|
|
MenuEntity.Elements[i].classList.remove("current");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function onRefChanged(ref, element, player) {
|
|
if(element.classList.contains("skip"))
|
|
{
|
|
var ErrorCount = 0;
|
|
if(!player.filter) { console.log("Missing filter_container div"); ErrorCount++; }
|
|
if(!player.filterState) { console.log("Missing filterState object"); ErrorCount++; }
|
|
if(ErrorCount > 0)
|
|
{
|
|
switch(ErrorCount)
|
|
{
|
|
case 1:
|
|
{ console.log("This should have been generated by Cinera along with the following element containing the \"skip\" class:"); } break;
|
|
default:
|
|
{ console.log("These should have been generated by Cinera along with the following element containing the \"skip\" class:"); } break;
|
|
}
|
|
console.log(element); return;
|
|
}
|
|
|
|
if(!player.filter.classList.contains("responsible"))
|
|
{
|
|
player.filter.classList.add("responsible");
|
|
}
|
|
|
|
for(var selector = 0; selector < element.classList.length; ++selector)
|
|
{
|
|
var elementClass = element.classList[selector];
|
|
if(elementClass.startsWith("off_"))
|
|
{
|
|
if(!player.filter.querySelector(".filter_content." + elementClass.replace(/^off_/, "")).classList.contains("responsible"))
|
|
{
|
|
player.filter.querySelector(".filter_content." + elementClass.replace(/^off_/, "")).classList.add("responsible");
|
|
}
|
|
}
|
|
if(elementClass.startsWith("cat_") || elementClass in player.filterState)
|
|
{
|
|
if(!player.filter.querySelector(".filter_mode").classList.add("responsible"))
|
|
{
|
|
player.filter.querySelector(".filter_mode").classList.add("responsible");
|
|
}
|
|
}
|
|
setTimeout(resetFade, 8000, player);
|
|
}
|
|
if(player && player.playing)
|
|
{
|
|
player.jumpToNextMarker();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
player.alignMenuWithTimestamp(ref, element, menu_id.QUOTES);
|
|
player.alignMenuWithTimestamp(ref, element, menu_id.REFERENCES);
|
|
}
|
|
}
|
|
|
|
Player.prototype.navigateFilter = function(filterItem) {
|
|
if(filterItem != this.Menus[menu_id.FILTER].Category.LastFocused)
|
|
{
|
|
this.unfocusUIElement(focus_level.ITEM);
|
|
}
|
|
|
|
this.focusUIElement(focus_level.ITEM, menu_id.FILTER, this.Menus[menu_id.FILTER].Category, filterItem);
|
|
if(filterItem.parentNode.classList.contains("filter_topics"))
|
|
{
|
|
this.Menus[menu_id.FILTER].Topic.LastFocused = this.Menus[menu_id.FILTER].Category.LastFocused;
|
|
}
|
|
else
|
|
{
|
|
this.Menus[menu_id.FILTER].Medium.LastFocused = this.Menus[menu_id.FILTER].Category.LastFocused;
|
|
}
|
|
}
|
|
|
|
Player.prototype.mouseOverReferenceOrQuoteIdentifier = function(MenuID, identifier) {
|
|
var MenuEntity = this.Menus[MenuID];
|
|
if(this.MenusFocused.Item && MenuEntity.Item.LastFocused != identifier.closest(".ref"))
|
|
{
|
|
this.unfocusUIElement(focus_level.ITEM);
|
|
}
|
|
this.focusUIElement(focus_level.ITEM, MenuID, MenuEntity.Item, identifier.closest(".ref"));
|
|
|
|
if(this.MenusFocused.Identifier && identifier != MenuEntity.Identifier.LastFocused)
|
|
{
|
|
this.unfocusUIElement(focus_level.IDENTIFIER);
|
|
}
|
|
this.focusUIElement(focus_level.IDENTIFIER, MenuID, MenuEntity.Identifier, identifier);
|
|
}
|
|
|
|
Player.prototype.mouseOverReferencesOrQuotes = function(MenuID, item) {
|
|
var MenuEntity = this.Menus[MenuID];
|
|
if(this.MenusFocused.Item && item != MenuEntity.Item.LastFocused)
|
|
{
|
|
this.unfocusUIElement(focus_level.ITEM);
|
|
}
|
|
this.focusUIElement(focus_level.ITEM, MenuID, MenuEntity.Item, item);
|
|
|
|
var ourIdentifiers = item.querySelectorAll(".timecode");
|
|
var weWereLastFocused = false;
|
|
for(var i = 0; i < ourIdentifiers.length; ++i)
|
|
{
|
|
if(ourIdentifiers[i] == MenuEntity.Identifier.LastFocused)
|
|
{
|
|
weWereLastFocused = true;
|
|
}
|
|
}
|
|
if(!weWereLastFocused)
|
|
{
|
|
this.unfocusUIElement(focus_level.IDENTIFIER);
|
|
}
|
|
this.focusUIElement(focus_level.IDENTIFIER, MenuID, MenuEntity.Identifier, getMostRecentCitation(this.currentTime, ourIdentifiers));
|
|
}
|
|
|
|
Player.prototype.mouseOverCredits = function(item) {
|
|
if(this.MenusFocused.Item && item != this.Menus[menu_id.CREDITS].Item.LastFocused)
|
|
{
|
|
this.unfocusUIElement(focus_level.ITEM);
|
|
}
|
|
this.focusUIElement(focus_level.ITEM, menu_id.CREDITS, this.Menus[menu_id.CREDITS].Item, item);
|
|
}
|
|
|
|
function mouseSkipToTimecode(player, time, ev)
|
|
{
|
|
player.setTimeThenPlay(parseFloat(time));
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
return false;
|
|
}
|
|
|
|
Player.prototype.handleMenuTogglerInteraction = function(menu, eventType)
|
|
{
|
|
if(!menu.classList.contains("visible") && eventType == "mouseenter" ||
|
|
menu.classList.contains("visible") && eventType == "mouseleave" ||
|
|
(eventType == "click" && !menu.classList.contains("cineraHelp")))
|
|
{
|
|
if(menu.classList.contains("quotes"))
|
|
{
|
|
this.toggleMenuVisibility(menu_id.QUOTES, trigger_id.MOUSE);
|
|
}
|
|
else if(menu.classList.contains("references"))
|
|
{
|
|
this.toggleMenuVisibility(menu_id.REFERENCES, trigger_id.MOUSE);
|
|
}
|
|
else if(menu.classList.contains("filter"))
|
|
{
|
|
this.toggleMenuVisibility(menu_id.FILTER, trigger_id.MOUSE);
|
|
}
|
|
else if(menu.classList.contains("link"))
|
|
{
|
|
this.toggleMenuVisibility(menu_id.LINK, trigger_id.MOUSE);
|
|
}
|
|
else if(menu.classList.contains("credits"))
|
|
{
|
|
this.toggleMenuVisibility(menu_id.CREDITS, trigger_id.MOUSE);
|
|
}
|
|
}
|
|
}
|