cinera: Share link (to current annotation)

This commit is contained in:
Matt Mascarenhas 2018-05-22 22:43:59 +01:00
parent 426cbfccba
commit ce367b00aa
4 changed files with 195 additions and 52 deletions

View File

@ -16,7 +16,7 @@ typedef struct
version CINERA_APP_VERSION = { version CINERA_APP_VERSION = {
.Major = 0, .Major = 0,
.Minor = 5, .Minor = 5,
.Patch = 51 .Patch = 52
}; };
// TODO(matt): Copy in the DB 3 stuff from cinera_working.c // TODO(matt): Copy in the DB 3 stuff from cinera_working.c
@ -1348,7 +1348,6 @@ SearchCredentials(buffer *CreditsMenu, bool *HasCreditsMenu, char *Person, char
{ {
CopyStringToBuffer(CreditsMenu, CopyStringToBuffer(CreditsMenu,
" <div class=\"menu credits\">\n" " <div class=\"menu credits\">\n"
" <div class=\"mouse_catcher\"></div>\n"
" <span>Credits</span>\n" " <span>Credits</span>\n"
" <div class=\"credits_container\">\n"); " <div class=\"credits_container\">\n");
@ -3433,7 +3432,6 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
CopyStringToBuffer(&ReferenceMenu, CopyStringToBuffer(&ReferenceMenu,
" <div class=\"menu references\">\n" " <div class=\"menu references\">\n"
" <span>References &#9660;</span>\n" " <span>References &#9660;</span>\n"
" <div class=\"mouse_catcher\"></div>\n"
" <div class=\"refs references_container\">\n"); " <div class=\"refs references_container\">\n");
if(BuildReference(ReferencesArray, RefIdentifier, UniqueRefs, CurrentRef, Anno) == RC_INVALID_REFERENCE) if(BuildReference(ReferencesArray, RefIdentifier, UniqueRefs, CurrentRef, Anno) == RC_INVALID_REFERENCE)
@ -3589,7 +3587,6 @@ AppendedIdentifier:
CopyStringToBuffer(&QuoteMenu, CopyStringToBuffer(&QuoteMenu,
" <div class=\"menu quotes\">\n" " <div class=\"menu quotes\">\n"
" <span>Quotes &#9660;</span>\n" " <span>Quotes &#9660;</span>\n"
" <div class=\"mouse_catcher\"></div>\n"
" <div class=\"refs quotes_container\">\n"); " <div class=\"refs quotes_container\">\n");
HasQuoteMenu = TRUE; HasQuoteMenu = TRUE;
@ -3969,6 +3966,13 @@ AppendedIdentifier:
" <div class=\"views_container\">\n" " <div class=\"views_container\">\n"
" <div class=\"view\" data-id=\"super\" title=\"SUPERtheatre mode\">&#127967;</div>\n" " <div class=\"view\" data-id=\"super\" title=\"SUPERtheatre mode\">&#127967;</div>\n"
" </div>\n" " </div>\n"
" </div>\n"
" <div class=\"menu link\">\n"
" <span>&#128279;</span>\n"
" <div class=\"link_container\">\n"
" <div id=\"cineraLinkMode\">Link to current annotation</div>\n"
" <textarea title=\"Click to copy to clipboard\" id=\"cineraLink\" readonly spellcheck=\"false\"></textarea>\n"
" </div>\n"
" </div>\n"); " </div>\n");
if(HasCreditsMenu) if(HasCreditsMenu)
@ -3992,7 +3996,7 @@ AppendedIdentifier:
if(HasFilterMenu) if(HasFilterMenu)
{ {
CopyStringToBuffer(&CollationBuffers->Menus, CopyStringToBuffer(&CollationBuffers->Menus,
" <span class=\"help_key\">z</span> <span class=\"help_text\">Toggle filter mode</span> <span class=\"help_key\">V</span> <span class=\"help_text\">Revert filter to original state</span>\n"); " <span class=\"help_key\">V</span> <span class=\"help_text\">Revert filter to original state</span> <span class=\"help_key\">Y</span> <span class=\"help_text\">Select link (requires manual Ctrl-c)</span>\n");
} }
else else
{ {
@ -4037,6 +4041,9 @@ AppendedIdentifier:
" <span class=\"help_key unavailable\">f</span> <span class=\"help_text unavailable\">Filter</span>\n"); " <span class=\"help_key unavailable\">f</span> <span class=\"help_text unavailable\">Filter</span>\n");
} }
CopyStringToBuffer(&CollationBuffers->Menus,
" <span class=\"help_key\">y</span> <span class=\"help_text\">Link</span>\n");
if(HasCreditsMenu) if(HasCreditsMenu)
{ {
CopyStringToBuffer(&CollationBuffers->Menus, CopyStringToBuffer(&CollationBuffers->Menus,
@ -4206,7 +4213,10 @@ AppendedIdentifier:
" <h2>Filter Menu</h2>\n" " <h2>Filter Menu</h2>\n"
" <span class=\"help_key\">x</span>, <span class=\"help_key word\">Space</span> <span class=\"help_text\">Toggle category and focus next</span><br>\n" " <span class=\"help_key\">x</span>, <span class=\"help_key word\">Space</span> <span class=\"help_text\">Toggle category and focus next</span><br>\n"
" <span class=\"help_key\">X</span>, <span class=\"help_key word modifier\">Shift</span><span class=\"help_key word\">Space</span> <span class=\"help_text\">Toggle category and focus previous</span><br>\n" " <span class=\"help_key\">X</span>, <span class=\"help_key word modifier\">Shift</span><span class=\"help_key word\">Space</span> <span class=\"help_text\">Toggle category and focus previous</span><br>\n"
" <span class=\"help_key\">v</span> <span class=\"help_text\">Invert topics / media as per focus</span>\n"); " <span class=\"help_key\">v</span> <span class=\"help_text\">Invert topics / media as per focus</span>\n"
"\n"
" <h2>Filter and Link Menus</h2>\n"
" <span class=\"help_key\">z</span> <span class=\"help_text\">Toggle filter / linking mode</span>\n");
} }
else else
{ {
@ -4214,7 +4224,10 @@ AppendedIdentifier:
" <h2><span class=\"unavailable\">Filter Menu</span></h2>\n" " <h2><span class=\"unavailable\">Filter Menu</span></h2>\n"
" <span class=\"help_key unavailable\">x</span>, <span class=\"help_key word unavailable\">Space</span> <span class=\"help_text unavailable\">Toggle category and focus next</span><br>\n" " <span class=\"help_key unavailable\">x</span>, <span class=\"help_key word unavailable\">Space</span> <span class=\"help_text unavailable\">Toggle category and focus next</span><br>\n"
" <span class=\"help_key unavailable\">X</span>, <span class=\"help_key word modifier unavailable\">Shift</span><span class=\"help_key word unavailable\">Space</span> <span class=\"help_text unavailable\">Toggle category and focus previous</span><br>\n" " <span class=\"help_key unavailable\">X</span>, <span class=\"help_key word modifier unavailable\">Shift</span><span class=\"help_key word unavailable\">Space</span> <span class=\"help_text unavailable\">Toggle category and focus previous</span><br>\n"
" <span class=\"help_key unavailable\">v</span> <span class=\"help_text unavailable\">Invert topics / media as per focus</span>\n"); " <span class=\"help_key unavailable\">v</span> <span class=\"help_text unavailable\">Invert topics / media as per focus</span>\n"
"\n"
" <h2><span class=\"unavailable\">Filter</span> and Link Menus</h2>\n"
" <span class=\"help_key\">z</span> <span class=\"help_text\">Toggle <span class=\"unavailable\">filter /</span> linking mode</span>\n");
} }
CopyStringToBuffer(&CollationBuffers->Menus, "\n"); CopyStringToBuffer(&CollationBuffers->Menus, "\n");

View File

@ -135,15 +135,8 @@
position: relative; position: relative;
} }
.cineraMenus > .menu .mouse_catcher {
position: absolute;
height: 100%;
width: 100%;
top: 0;
right: 0;
}
.cineraMenus > .menu.filter.responsible, .cineraMenus > .menu.filter.responsible,
.cineraMenus > .menu.link.responsible,
.cineraMenus .filter_content.responsible, .cineraMenus .filter_content.responsible,
.cineraMenus .filter_content.responsible .cineraText, .cineraMenus .filter_content.responsible .cineraText,
.cineraMenus > .menu > .filter_container .filter_mode.responsible { .cineraMenus > .menu > .filter_container .filter_mode.responsible {
@ -249,9 +242,11 @@
display: block; display: block;
} }
.cineraMenus > .menu .refs, .cineraMenus > .menu .quotes_container,
.cineraMenus > .menu .references_container,
.cineraMenus > .menu .filter_container, .cineraMenus > .menu .filter_container,
.cineraMenus > .menu .views_container, .cineraMenus > .menu .views_container,
.cineraMenus > .menu .link_container,
.cineraMenus > .menu .credits_container { .cineraMenus > .menu .credits_container {
border: 1px solid; border: 1px solid;
border-top: none; border-top: none;
@ -265,7 +260,8 @@
z-index: 1; z-index: 1;
} }
.cineraMenus > .menu .refs { .cineraMenus > .menu .refs,
.cineraMenus > .menu .link_container {
width: 350px; width: 350px;
} }
@ -277,13 +273,7 @@
min-width: 240px; min-width: 240px;
} }
/*.title > .menu:hover .refs,*/ .cineraMenus > .menu .visible {
.cineraMenus > .menu.quotes .refs.visible,
.cineraMenus > .menu.references .refs.visible,
/*.title > .menu:hover .filter_container,*/
.cineraMenus > .menu.filter .filter_container.visible,
.cineraMenus > .menu.credits .credits_container.visible {
/*.title > .menu:hover .credits_container {*/
display: block; display: block;
} }
@ -291,15 +281,15 @@
flex-direction: column; flex-direction: column;
} }
.cineraMenus > .menu {
cursor: default;
}
.cineraMenus > .menu > .view, .cineraMenus > .menu > .view,
.cineraMenus > .menu > .views_container .view { .cineraMenus > .menu > .views_container .view {
cursor: pointer; cursor: pointer;
} }
.cineraMenus > .menu > .credits_container .credit {
cursor: default;
}
.cineraMenus > .menu > .credits_container .credit .person { .cineraMenus > .menu > .credits_container .credit .person {
flex-grow: 1; flex-grow: 1;
text-decoration: none; text-decoration: none;
@ -320,10 +310,18 @@
} }
.cineraMenus > .menu > .refs .ref .timecode, .cineraMenus > .menu > .refs .ref .timecode,
.cineraMenus > .menu > .filter_container .filter_mode { .cineraMenus > .menu > .filter_container .filter_mode,
.cineraMenus > .menu > .link_container #cineraLinkMode {
font-size: 12px; font-size: 12px;
} }
.cineraMenus > .menu > .filter_container .filter_mode,
.cineraMenus > .menu > .link_container #cineraLinkMode {
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}
.cineraMenus > .menu > .refs .ref .timecode { .cineraMenus > .menu > .refs .ref .timecode {
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
@ -379,7 +377,8 @@
margin-right: 4px; margin-right: 4px;
} }
.cineraMenus > .menu > .filter_container .filter_mode { .cineraMenus > .menu > .filter_container .filter_mode,
.cineraMenus > .menu > .link_container #cineraLinkMode {
cursor: pointer; cursor: pointer;
border-bottom: 1px solid; border-bottom: 1px solid;
text-align: center; text-align: center;
@ -448,6 +447,15 @@
font-variant: small-caps; font-variant: small-caps;
} }
.cineraMenus > .menu > .link_container #cineraLink {
border: 0;
cursor: pointer;
height: 100%;
padding: 4px;
resize: none;
width: 100%;
}
.cineraPlayerContainer { .cineraPlayerContainer {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -131,6 +131,7 @@ var cineraProps = {
var viewsMenu = titleBar.querySelector(".views"); var viewsMenu = titleBar.querySelector(".views");
if(viewsMenu) if(viewsMenu)
{ {
menuState.push(viewsMenu);
var viewsContainer = viewsMenu.querySelector(".views_container"); var viewsContainer = viewsMenu.querySelector(".views_container");
viewsMenu.addEventListener("mouseenter", function(ev) { viewsMenu.addEventListener("mouseenter", function(ev) {
handleMouseOverViewsMenu(); handleMouseOverViewsMenu();
@ -159,6 +160,26 @@ if(viewsMenu)
} }
} }
var baseURL = location.hash ? (location.toString().substr(0, location.toString().length - location.hash.length)) : location;
var linkMenu = titleBar.querySelector(".link_container");
linkAnnotation = true;
if(linkMenu)
{
menuState.push(linkMenu);
var linkMode = linkMenu.querySelector("#cineraLinkMode");
var link = linkMenu.querySelector("#cineraLink");
linkMode.addEventListener("click", function(ev) {
toggleLinkMode(linkMode, link);
});
link.addEventListener("click", function(ev) {
CopyToClipboard(link);
toggleMenuVisibility(linkMenu);
});
}
var creditsMenu = titleBar.querySelector(".credits_container"); var creditsMenu = titleBar.querySelector(".credits_container");
if(creditsMenu) if(creditsMenu)
{ {
@ -237,7 +258,7 @@ document.addEventListener("keydown", function(ev) {
key = "capitalSpace"; key = "capitalSpace";
} }
if(handleKey(key) == true && focusedElement) if(!ev.getModifierState("Control") && handleKey(key) == true && focusedElement)
{ {
ev.preventDefault(); ev.preventDefault();
} }

View File

@ -267,6 +267,7 @@ Player.prototype.doFrame = function() {
} }
this.nextFrame = requestAnimationFrame(this.doFrame.bind(this)); this.nextFrame = requestAnimationFrame(this.doFrame.bind(this));
updateLink();
}; };
Player.prototype.onYoutubePlayerReady = function() { Player.prototype.onYoutubePlayerReady = function() {
@ -331,13 +332,83 @@ Player.youtubePlayerCount = 0;
// NOTE(matt): Hereafter is my stuff. Beware! // NOTE(matt): Hereafter is my stuff. Beware!
function toggleFilterMode() {
if(filterMode == "inclusive")
{
filterModeElement.classList.remove("inclusive");
filterModeElement.classList.add("exclusive");
filterMode = "exclusive";
}
else
{
filterModeElement.classList.remove("exclusive");
filterModeElement.classList.add("inclusive");
filterMode = "inclusive";
}
applyFilter();
}
function updateLink()
{
if(link && player)
{
if(linkAnnotation == true)
{
if(player.currentMarker)
{
link.value = baseURL + "#" + player.currentMarker.timestamp;
}
else
{
link.value = baseURL;
}
}
else
{
link.value = baseURL + "#" + Math.round(player.youtubePlayer.getCurrentTime());
}
}
}
function toggleLinkMode(linkMode, link)
{
linkAnnotation = !linkAnnotation;
if(linkAnnotation == true)
{
linkMode.textContent = "Link to current annotation";
}
else
{
linkMode.textContent = "Link to nearest second";
}
updateLink();
}
function toggleFilterOrLinkMode()
{
for(menuIndex in menuState)
{
if(menuState[menuIndex].classList.contains("filter_container") && menuState[menuIndex].classList.contains("visible"))
{
toggleFilterMode();
}
if(menuState[menuIndex].classList.contains("link_container") && menuState[menuIndex].classList.contains("visible"))
{
toggleLinkMode(linkMode, link);
}
}
}
function toggleMenuVisibility(element) { function toggleMenuVisibility(element) {
if(element.classList.contains("visible")) if(element.classList.contains("visible"))
{ {
element.classList.remove("visible"); element.classList.remove("visible");
element.parentNode.classList.remove("visible"); element.parentNode.classList.remove("visible");
if(focusedElement)
{
focusedElement.classList.remove("focused"); focusedElement.classList.remove("focused");
focusedElement = null; focusedElement = null;
}
if(focusedIdentifier) if(focusedIdentifier)
{ {
focusedIdentifier.classList.remove("focused"); focusedIdentifier.classList.remove("focused");
@ -536,6 +607,27 @@ function toggleSuperTheatreMode()
player.updateSize(); player.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();
}
function CopyToClipboard(inputElement)
{
SelectText(inputElement);
document.execCommand("copy");
AscribeTemporaryResponsibility(linkMenu.parentNode, 8000);
}
function handleKey(key) { function handleKey(key) {
var gotKey = true; var gotKey = true;
switch (key) { switch (key) {
@ -557,6 +649,13 @@ function handleKey(key) {
toggleMenuVisibility(filterMenu) toggleMenuVisibility(filterMenu)
} }
} break; } break;
case "y": {
if(linkMenu)
{
toggleMenuVisibility(linkMenu)
}
break;
}
case "c": { case "c": {
if(creditsMenu) if(creditsMenu)
{ {
@ -917,7 +1016,7 @@ function handleKey(key) {
} break; } break;
case "z": { case "z": {
toggleFilterMode(); toggleFilterOrLinkMode();
} break; } break;
case "v": { case "v": {
@ -960,6 +1059,20 @@ function handleKey(key) {
location = nextEpisode.href; location = nextEpisode.href;
} }
} break; } break;
case 'Y': {
if(cineraLink)
{
if(linkAnnotation == false && player.playing)
{
player.pause();
}
if(linkMenu && !linkMenu.classList.contains("visible"))
{
toggleMenuVisibility(linkMenu);
}
SelectText(cineraLink);
}
}
default: { default: {
gotKey = false; gotKey = false;
} break; } break;
@ -998,22 +1111,6 @@ function applyFilter() {
} }
} }
function toggleFilterMode() {
if(filterMode == "inclusive")
{
filterModeElement.classList.remove("inclusive");
filterModeElement.classList.add("exclusive");
filterMode = "exclusive";
}
else
{
filterModeElement.classList.remove("exclusive");
filterModeElement.classList.add("inclusive");
filterMode = "inclusive";
}
applyFilter();
}
function filterItemToggle(filterItem) { function filterItemToggle(filterItem) {
var selectedCategory = filterItem.classList[1]; var selectedCategory = filterItem.classList[1];
filterState[selectedCategory].off = !filterState[selectedCategory].off; filterState[selectedCategory].off = !filterState[selectedCategory].off;
@ -1356,6 +1453,10 @@ function handleMouseOverMenu(menu, eventType)
{ {
toggleMenuVisibility(filterMenu); toggleMenuVisibility(filterMenu);
} }
else if(menu.classList.contains("link"))
{
toggleMenuVisibility(linkMenu);
}
else if(menu.classList.contains("credits")) else if(menu.classList.contains("credits"))
{ {
toggleMenuVisibility(creditsMenu); toggleMenuVisibility(creditsMenu);