From 545938d7666dddb5924c1264f68157dd3bfbfc86 Mon Sep 17 00:00:00 2001 From: Matt Mascarenhas Date: Thu, 4 Feb 2021 00:13:55 +0000 Subject: [PATCH] cinera.web: Fix issues (on mobile) with new layout Both pages: Derive reliable window dimensions ourselves Set the orientation from the window dimensions Use "box-sizing: content-box" on the help keys, to fix sizing Search page: Support irregular (i.e. non-square) grids General sizing fixes Fix text fitting when toggling back from List to Grid view Fix text fitting when textNode would overflow container Correctly compute optimal grid size after orientation change Rename .text to .cineraText to avoid CSS selector clash Only add click events for the main set of buttons (not its clone) Player page: Size the video and timestamps bar more sensibly --- cinera/cinera.c | 4 +- cinera/cinera.css | 48 +- cinera/cinera_player_post.js | 43 +- cinera/cinera_player_pre.js | 104 ++- cinera/cinera_pre.js | 102 ++- cinera/cinera_search_post.js | 5 +- cinera/cinera_search_pre.js | 1683 +++++++++++++++++++--------------- 7 files changed, 1161 insertions(+), 828 deletions(-) diff --git a/cinera/cinera.c b/cinera/cinera.c index 6bb0db4..41f7ff7 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -23,7 +23,7 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 8, - .Patch = 1 + .Patch = 2 }; #include // NOTE(matt): varargs @@ -13507,6 +13507,7 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0); AppendStringToBuffer(B, Wrap0(" class=\"key_block\">")); + OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, 0); AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("1"), TRUE); AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("q"), TRUE); @@ -13535,6 +13536,7 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P AppendHelpKeyToBuffer(B, &IndentationLevel, Wrap0("v"), TRUE); CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); + CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // key_block CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // help_paragraph diff --git a/cinera/cinera.css b/cinera/cinera.css index 2e15f87..123c9d3 100644 --- a/cinera/cinera.css +++ b/cinera/cinera.css @@ -142,20 +142,6 @@ ul.cineraNavPlain li.current > a { order: 2; } -#cineraIndex .cineraTraversal .cineraButton -{ - /* TODO(matt): Do the cineraTraversal as a flex box, to auto-size these buttons? */ - height: 42px; - width: 42px; - - padding: 2px; - margin: 2px; - - display: inline-flex; - align-items: center; - justify-content: center; -} - #cineraIndex.anim .cineraTraversal, #cineraIndex.anim .cineraTraversal * p { @@ -179,6 +165,20 @@ ul.cineraNavPlain li.current > a { transform: rotate(180deg); } +#cineraIndex .cineraTraversal .cineraButton +{ + box-sizing: border-box; + display: inline-flex; + align-items: center; + justify-content: center; + + padding: 2px; + margin: 2px; + + height: 42px; + width: 42px; +} + #cineraIndex .cineraTraversal * p { transform: rotate(0deg); @@ -274,6 +274,7 @@ ul.cineraNavPlain li.current > a { } .cineraQueryContainer #query { + width: 0px; flex-grow: 1; } @@ -281,6 +282,7 @@ ul.cineraNavPlain li.current > a { position: absolute; top: 2px; right: 5px; + font-size: small; color: #000000; height: 100%; display: none; @@ -345,14 +347,23 @@ ul.cineraNavPlain li.current > a { display: flex; backface-visibility: hidden; -webkit-backface-visibility: hidden; + overflow: hidden; } #cineraIndex #cineraIndexGrid .cineraButton.subdivision .head-item, #cineraIndex #cineraIndexGrid .cineraButton.subdivision .tail-item { + display: flex; width: 100%; height: 50%; - display: flex; +} + +#cineraIndex #cineraIndexGrid .cineraButton.subdivision .head-item p, +#cineraIndex #cineraIndexGrid .cineraButton.subdivision .tail-item p +{ + border: 0; + margin: 0; + padding: 0; } #cineraIndex #cineraIndexGrid .cineraButton.subdivision.leaf @@ -518,7 +529,7 @@ ul.cineraNavPlain li.current > a { left: 50%; transform: translate(-50%, -50%); max-height: 97%; - overflow-y: scroll; + overflow-y: auto; } .cineraHelp .help_container.visible { @@ -526,14 +537,15 @@ ul.cineraNavPlain li.current > a { } .cineraHelp .help_container .help_key { + box-sizing: content-box; font-family: Inconsolata; font-size: 16px; border: 1px solid; display: inline-block; background-color: #111111; /* Per project */ border-radius: 4px; - height: 16px; - width: 16px; + min-height: 1em; + min-width: 1em; padding: 4px; line-height: 16px; margin: 2px; diff --git a/cinera/cinera_player_post.js b/cinera/cinera_player_post.js index 56d79ab..5c478eb 100644 --- a/cinera/cinera_player_post.js +++ b/cinera/cinera_player_post.js @@ -21,6 +21,9 @@ var sourceMenus = null; var helpButton = null; var helpDocumentation = null; +// NOTE(matt): One set of markers per page. There is code to support multiple, which we may want to extend everywhere +var MarkersContainer = cinera.querySelector(".markers_container"); + var views = { REGULAR: 0, THEATRE: 1, @@ -32,7 +35,7 @@ var devices = { MOBILE: 1, }; -var cineraProps = { +var CineraProps = { C: null, V: views.REGULAR, Z: null, @@ -46,11 +49,12 @@ var cineraProps = { Display: null, FlexDirection: null, JustifyContent: null, - O: window.orientation, + O: null, D: IsMobile() ? devices.MOBILE : devices.DESKTOP, ScrollX: null, ScrollY: null, }; +CineraProps.O = GetRealOrientation(CineraProps.IsMobile); if(titleBar) { @@ -169,7 +173,7 @@ if(titleBar) } viewsMenu = titleBar.querySelector(".views"); - if(viewsMenu && cineraProps.D !== devices.MOBILE) + if(viewsMenu && CineraProps.D !== devices.MOBILE) { menuState.push(viewsMenu); var viewsContainer = viewsMenu.querySelector(".views_container"); @@ -276,7 +280,7 @@ var MobileCineraContentRule = GetOrSetRule(MobileCineraContentRuleSelector); var MenuContainerRuleSelector = ".cineraMenus > .menu .quotes_container, .cineraMenus > .menu .references_container, .cineraMenus > .menu .filter_container, .cineraMenus > .menu .views_container, .cineraMenus > .menu .link_container, .cineraMenus > .menu .credits_container"; var MenuContainerRule = GetOrSetRule(MenuContainerRuleSelector); -if(cineraProps.D == devices.MOBILE) +if(CineraProps.D == devices.MOBILE) { InitMobileStyle(); } @@ -288,7 +292,7 @@ else var player = new Player(playerContainer, onRefChanged); -if(cineraProps.D == devices.MOBILE) +if(CineraProps.D == devices.MOBILE) { ConnectMobileControls(player); } @@ -302,7 +306,28 @@ if(viewsMenu && localStorage.getItem(cineraViewStorageItem)) InitScrollEventListener(cinera); -window.addEventListener("resize", function() { player.updateSize(); }); +window.addEventListener("resize", function() { + if(CineraProps.IsMobile) + { + setTimeout(player.updateSize, 512); + } + else + { + player.updateSize(); + } +}); + +window.onorientationchange = function() { + if(CineraProps.IsMobile) + { + setTimeout(player.updateSize, 512); + } + else + { + player.updateSize(); + } +}; + document.addEventListener("keydown", function(ev) { var key = ev.key; if(ev.getModifierState("Shift") && key == " ") @@ -350,9 +375,3 @@ else if(lastAnnotation = localStorage.getItem(lastAnnotationStorageItem)) { player.setTime(lastAnnotation); } - -window.onorientationchange = function() -{ - cineraProps.O = window.orientation; - player.updateSize(); -}; diff --git a/cinera/cinera_player_pre.js b/cinera/cinera_player_pre.js index ee1952e..e255dea 100644 --- a/cinera/cinera_player_pre.js +++ b/cinera/cinera_player_pre.js @@ -207,7 +207,7 @@ function sizeAndPositionMenuContainer(TitleBar, SizerElement, Menu) var ContainerDimX = SizerElementDimX; var ContainerDimY = SizerElementDimY; - switch(cineraProps.O) + switch(CineraProps.O) { case orientations.PORTRAIT: { @@ -286,14 +286,18 @@ ComputeTallest(Elements, UnhidingClass) function ComputeAndSetTallest(Selector, Elements, UnhidingClass) { + var Result; Selector.style.height = "unset"; - Selector.style.height = ComputeTallest(Elements, UnhidingClass) + "px"; + Result = ComputeTallest(Elements, UnhidingClass); + Selector.style.height = Result + "px"; + return Result; } function ApplyMobileStyle(player) { - var MaxWidth = MaxWidthOfElement(cinera); - var MaxHeight = MaxHeightOfElement(cinera); + var WindowDim = DeriveReliableWindowDimensions(); + var MaxWidth = cinera.offsetWidth; + var MaxHeight = MaxHeightOfElement(cinera, WindowDim); var IndicesBar = playerContainer.querySelector(".markers_container"); var Markers = IndicesBar.querySelector(".markers"); @@ -305,7 +309,7 @@ function ApplyMobileStyle(player) CineraContentWidth -= EpisodeMarkers[i].offsetWidth; } - switch(cineraProps.O) + switch(CineraProps.O) { case orientations.PORTRAIT: { @@ -326,28 +330,29 @@ function ApplyMobileStyle(player) } break; } + var HeightOfTallestIndex; if(MobileCineraContentRule !== undefined) { MobileCineraContentRule.style.width = CineraContentWidth + "px"; var MarkerList = Markers.querySelectorAll(".marker"); - ComputeAndSetTallest(MobileCineraContentRule, MarkerList, "current"); + HeightOfTallestIndex = ComputeAndSetTallest(MobileCineraContentRule, MarkerList, "current"); + IndicesBar.style.height = HeightOfTallestIndex + "px"; + Markers.style.width = CineraContentWidth + "px"; } - var VideoMaxDimX = null; - var VideoMaxDimY = null; + var VideoMaxDimX = CineraContentWidth; + var VideoMaxDimY = MaxHeight - HeightOfTallestIndex; - switch(cineraProps.O) + switch(CineraProps.O) { case orientations.PORTRAIT: { - VideoMaxDimX = MaxWidth; - VideoMaxDimY = MaxHeight - IndicesBar.offsetHeight - titleBar.offsetHeight; + VideoMaxDimY -= titleBar.offsetHeight; } break; case orientations.LANDSCAPE_LEFT: case orientations.LANDSCAPE_RIGHT: { - VideoMaxDimX = MaxWidth - titleBar.offsetWidth; - VideoMaxDimY = MaxHeight - IndicesBar.offsetHeight; + VideoMaxDimX -= titleBar.offsetWidth; } break; } @@ -477,7 +482,8 @@ ConnectMobileControls(player) Player.prototype.updateSize = function() { var width = 0; var height = 0; - if(cineraProps.D === devices.DESKTOP) + CineraProps.O = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile); + if(CineraProps.D === devices.DESKTOP) { width = this.videoContainer.offsetWidth; height = width / 16 * 9; // TODO(matt): Get the aspect ratio from the video itself? @@ -862,7 +868,7 @@ function toggleMenuVisibility(element) { function handleMouseOverViewsMenu() { - switch(cineraProps.V) + switch(CineraProps.V) { case views.REGULAR: case views.THEATRE: @@ -904,24 +910,24 @@ function leaveFullScreen_() } function toggleTheatreMode() { - switch(cineraProps.V) + switch(CineraProps.V) { case views.REGULAR: { - cineraProps.C = cinera.style.backgroundColor; - cineraProps.Z = cinera.style.zIndex; - cineraProps.X = cinera.style.left; - cineraProps.Y = cinera.style.top; - cineraProps.W = cinera.style.width; - cineraProps.mW = cinera.style.maxWidth; - cineraProps.H = cinera.style.height; - cineraProps.mH = cinera.style.maxHeight; - cineraProps.P = cinera.style.position; - cineraProps.Display = cinera.style.display; - cineraProps.FlexDirection = cinera.style.flexDirection; - cineraProps.JustifyContent = cinera.style.justifyContent; - cineraProps.ScrollX = window.scrollX; - cineraProps.ScrollY = window.scrollY; + CineraProps.C = cinera.style.backgroundColor; + CineraProps.Z = cinera.style.zIndex; + CineraProps.X = cinera.style.left; + CineraProps.Y = cinera.style.top; + CineraProps.W = cinera.style.width; + CineraProps.mW = cinera.style.maxWidth; + CineraProps.H = cinera.style.height; + CineraProps.mH = cinera.style.maxHeight; + CineraProps.P = cinera.style.position; + CineraProps.Display = cinera.style.display; + CineraProps.FlexDirection = cinera.style.flexDirection; + CineraProps.JustifyContent = cinera.style.justifyContent; + CineraProps.ScrollX = window.scrollX; + CineraProps.ScrollY = window.scrollY; cinera.style.backgroundColor = "#000"; cinera.style.zIndex = 64; @@ -939,43 +945,43 @@ function toggleTheatreMode() { viewItems[0].setAttribute("data-id", "regular"); viewItems[0].setAttribute("title", "Regular mode"); viewItems[0].firstChild.nodeValue = "📺"; - } cineraProps.V = views.THEATRE; localStorage.setItem(cineraViewStorageItem, views.THEATRE); break; + } CineraProps.V = views.THEATRE; localStorage.setItem(cineraViewStorageItem, views.THEATRE); break; case views.SUPERTHEATRE: { leaveFullScreen_(); } case views.THEATRE: { - cinera.style.backgroundColor = cineraProps.C; - cinera.style.zIndex = cineraProps.Z; - cinera.style.left = cineraProps.X; - cinera.style.top = cineraProps.Y; - cinera.style.width = cineraProps.W; - cinera.style.maxWidth = cineraProps.mW; - cinera.style.height = cineraProps.H; - cinera.style.maxHeight = cineraProps.mH; - cinera.style.position = cineraProps.P; - cinera.style.display = cineraProps.Display; - cinera.style.flexDirection = cineraProps.FlexDirection; - cinera.style.justifyContent = cineraProps.JustifyContent; + cinera.style.backgroundColor = CineraProps.C; + cinera.style.zIndex = CineraProps.Z; + cinera.style.left = CineraProps.X; + cinera.style.top = CineraProps.Y; + cinera.style.width = CineraProps.W; + cinera.style.maxWidth = CineraProps.mW; + cinera.style.height = CineraProps.H; + cinera.style.maxHeight = CineraProps.mH; + cinera.style.position = CineraProps.P; + cinera.style.display = CineraProps.Display; + cinera.style.flexDirection = CineraProps.FlexDirection; + cinera.style.justifyContent = CineraProps.JustifyContent; window.scroll( { - top: cineraProps.ScrollY, - left: cineraProps.ScrollX + top: CineraProps.ScrollY, + left: CineraProps.ScrollX } ); viewItems[0].setAttribute("data-id", "theatre"); viewItems[0].setAttribute("title", "Theatre mode"); viewItems[0].firstChild.nodeValue = "🎭"; - } cineraProps.V = views.REGULAR; localStorage.removeItem(cineraViewStorageItem); break; + } CineraProps.V = views.REGULAR; localStorage.removeItem(cineraViewStorageItem); break; } player.updateSize(); } function toggleSuperTheatreMode() { - switch(cineraProps.V) + switch(CineraProps.V) { case views.REGULAR: { @@ -984,12 +990,12 @@ function toggleSuperTheatreMode() case views.THEATRE: { enterFullScreen_(); - } cineraProps.V = views.SUPERTHEATRE; localStorage.setItem(cineraViewStorageItem, views.SUPERTHEATRE); break; + } CineraProps.V = views.SUPERTHEATRE; localStorage.setItem(cineraViewStorageItem, views.SUPERTHEATRE); break; case views.SUPERTHEATRE: { leaveFullScreen_(); toggleTheatreMode(); - } cineraProps.V = views.REGULAR; localStorage.removeItem(cineraViewStorageItem); break; + } CineraProps.V = views.REGULAR; localStorage.removeItem(cineraViewStorageItem); break; } player.updateSize(); } diff --git a/cinera/cinera_pre.js b/cinera/cinera_pre.js index 14a0c83..7eda733 100644 --- a/cinera/cinera_pre.js +++ b/cinera/cinera_pre.js @@ -4,6 +4,73 @@ var orientations = { LANDSCAPE_RIGHT: -90, }; +function +DeriveReliableWindowDimensions() +{ + // https://www.howtocreate.co.uk/tutorials/javascript/browserwindow + var Result = { + X: null, + Y: null, + }; + + var DisplaySettings = []; + for(var i = 0; i < document.body.children.length; ++i) + { + var Child = document.body.children[i]; + DisplaySettings.push(Child.style.display); + Child.style.display = "none"; + } + + var Element = document.createElement("div"); + Element.style.position = "fixed"; + Element.style.top = 0; + Element.style.right = 0; + Element.style.bottom = 0; + Element.style.left = 0; + Element.style.zOffset = -1; + Element.style.opacity = 0; + var ElementInPlace = document.body.appendChild(Element); + Result.X = ElementInPlace.offsetWidth; + Result.Y = ElementInPlace.offsetHeight; + ElementInPlace.remove(); + + for(var i = 0; i < document.body.children.length; ++i) + { + var Child = document.body.children[i]; + Child.style.display = DisplaySettings.shift(); + } + + return Result; +} + +function +GetRealOrientation(PreferredLandscape, IsMobile) +{ + var Result = window.orientation; + var WindowDim = { + X: null, + Y: null, + }; + if(IsMobile) + { + WindowDim = DeriveReliableWindowDimensions(); + } + else + { + WindowDim.X = document.body.clientWidth; + WindowDim.Y = document.body.clientHeight; + } + if(WindowDim.Y > WindowDim.X) + { + Result = orientations.PORTRAIT; + } + else if(Result == undefined || Result == orientations.PORTRAIT) + { + Result = PreferredLandscape; + } + return Result; +} + var DebugConsoleMessageCount = 0; function Say(Message) { @@ -275,7 +342,7 @@ function getElementYOffsetFromPage(el) { } function -MaxWidthOfElement(Element) +MaxWidthOfElement(Element, WindowDim) { var Result = 0; var OriginalWidth = Element.style.width; @@ -283,21 +350,31 @@ MaxWidthOfElement(Element) var Max = parseInt(window.getComputedStyle(Element).width); Element.style.width = "unset"; var Default = parseInt(window.getComputedStyle(Element).width); - Element.style.width = OriginalWidth; - if(Max > window.innerWidth || Max == Default) + var InnerWidth = WindowDim ? WindowDim.X : document.body.clientWidth; + + if(Max > InnerWidth || Max == Default) { - Result = window.innerWidth; + Result = InnerWidth; + } else { Result = Max; } + + Element.style.width = Result + "px"; + if(Element.scrollWidth > Element.clientWidth) + { + Result = Element.clientWidth; + } + + Element.style.width = OriginalWidth; return Result; } function -MaxHeightOfElement(Element) +MaxHeightOfElement(Element, WindowDim) { var Result = 0; var OriginalHeight = Element.style.height; @@ -305,16 +382,25 @@ MaxHeightOfElement(Element) var Max = parseInt(window.getComputedStyle(Element).height); Element.style.height = "unset"; var Default = parseInt(window.getComputedStyle(Element).height); - Element.style.height = OriginalHeight; - if(Max > window.innerHeight || Max == Default) + var InnerHeight = WindowDim ? WindowDim.Y : document.body.clientHeight; + + if(Max > InnerHeight || Max == Default) { - Result = window.innerHeight; + Result = InnerHeight; } else { Result = Max; } + + Element.style.height = Result + "px"; + if(Element.scrollHeight > Element.clientHeight) + { + Result = Element.clientHeight; + } + + Element.style.height = OriginalHeight; return Result; } diff --git a/cinera/cinera_search_post.js b/cinera/cinera_search_post.js index e415e3b..3c7c246 100644 --- a/cinera/cinera_search_post.js +++ b/cinera/cinera_search_post.js @@ -1,4 +1,5 @@ document.body.style.overflowY = "scroll"; +CineraProps.Orientation = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile); // Element Selection // @@ -48,10 +49,12 @@ SyncNavState(); // NOTE(matt): Listeners // +BindControlKeys(); +BindGridKeys(Nav.GridSize); BindControls(); InitResizeEventListener(); InitOrientationChangeListener(); -InitScrollEventListener(Nav.Nexus); +InitScrollEventListener(Nav.Grid); // //// diff --git a/cinera/cinera_search_pre.js b/cinera/cinera_search_pre.js index 08144a3..630e29e 100644 --- a/cinera/cinera_search_pre.js +++ b/cinera/cinera_search_pre.js @@ -2,8 +2,7 @@ // var CineraProps = { IsMobile: IsMobile(), - Orientation: window.orientation, - + Orientation: null, }; var Search = { @@ -680,8 +679,17 @@ var Nav = { Nexus: null, GridContainer: null, ButtonsContainer: null, - GridSize: null, - GridWidth: null, + GridSize: { + X: null, + Y: null, + }, + GridMinCellsPerDimension: 1, + GridMaxCellsPerDimension: 4, + GridDim: { + X: null, + Y: null, + }, + MinButtonDim: 100, ButtonDim: null, GridColumnGap: null, GridRowGap: null, @@ -855,23 +863,74 @@ SetHelpKeyAvailability(GridSize) Nav.Controls.HelpKeys[i].classList.remove("unavailable"); } - if(GridSize < 4) + /* NOTE(matt): Key layout: + 0 4 8 12 + 1 5 9 13 + 2 6 10 14 + 3 7 11 15 + */ + + if(GridSize.X < 4) { - Nav.Controls.HelpKeys[3].classList.add("unavailable"); - Nav.Controls.HelpKeys[7].classList.add("unavailable"); - Nav.Controls.HelpKeys[11].classList.add("unavailable"); Nav.Controls.HelpKeys[12].classList.add("unavailable"); Nav.Controls.HelpKeys[13].classList.add("unavailable"); Nav.Controls.HelpKeys[14].classList.add("unavailable"); Nav.Controls.HelpKeys[15].classList.add("unavailable"); - if(GridSize < 3) + if(GridSize.X < 3) { - Nav.Controls.HelpKeys[2].classList.add("unavailable"); - Nav.Controls.HelpKeys[6].classList.add("unavailable"); Nav.Controls.HelpKeys[8].classList.add("unavailable"); Nav.Controls.HelpKeys[9].classList.add("unavailable"); Nav.Controls.HelpKeys[10].classList.add("unavailable"); + Nav.Controls.HelpKeys[11].classList.add("unavailable"); + + if(GridSize.X < 2) + { + Nav.Controls.HelpKeys[4].classList.add("unavailable"); + Nav.Controls.HelpKeys[5].classList.add("unavailable"); + Nav.Controls.HelpKeys[6].classList.add("unavailable"); + Nav.Controls.HelpKeys[7].classList.add("unavailable"); + + if(GridSize.X < 1) + { + Nav.Controls.HelpKeys[0].classList.add("unavailable"); + Nav.Controls.HelpKeys[1].classList.add("unavailable"); + Nav.Controls.HelpKeys[2].classList.add("unavailable"); + Nav.Controls.HelpKeys[3].classList.add("unavailable"); + } + } + } + } + + if(GridSize.Y < 4) + { + Nav.Controls.HelpKeys[3].classList.add("unavailable"); + Nav.Controls.HelpKeys[7].classList.add("unavailable"); + Nav.Controls.HelpKeys[11].classList.add("unavailable"); + Nav.Controls.HelpKeys[15].classList.add("unavailable"); + + if(GridSize.Y < 3) + { + Nav.Controls.HelpKeys[2].classList.add("unavailable"); + Nav.Controls.HelpKeys[6].classList.add("unavailable"); + Nav.Controls.HelpKeys[10].classList.add("unavailable"); + Nav.Controls.HelpKeys[14].classList.add("unavailable"); + + if(GridSize.Y < 2) + { + Nav.Controls.HelpKeys[1].classList.add("unavailable"); + Nav.Controls.HelpKeys[5].classList.add("unavailable"); + Nav.Controls.HelpKeys[9].classList.add("unavailable"); + Nav.Controls.HelpKeys[13].classList.add("unavailable"); + + if(GridSize.Y < 1) + { + Nav.Controls.HelpKeys[0].classList.add("unavailable"); + Nav.Controls.HelpKeys[4].classList.add("unavailable"); + Nav.Controls.HelpKeys[8].classList.add("unavailable"); + Nav.Controls.HelpKeys[12].classList.add("unavailable"); + } + } } } } @@ -895,17 +954,29 @@ SyncNavState() if(StateBitIsSet(state_bit.SORT_REVERSED)) { Sort(true); } // Nav.ViewType is initialised to view_type.GRID, so we needn't do anything if the Nav.State is also on Grid - if(StateBitIsSet(state_bit.VIEW_LIST)) { ToggleView(); } + if(StateBitIsSet(state_bit.VIEW_LIST) || !GridSizeIsSupported(Nav.GridSize)) + { + ToggleView(); + } } else { Nav.Controls.Save.textContent = "Save Settings: ✘"; + // Nav.ViewType was initialised to view_type.GRID + if(!GridSizeIsSupported(Nav.GridSize)) + { + ToggleView(); + } } } else { Nav.State = 0; SetStateBit(state_bit.VIEW_GRID); // NOTE(matt): Nav.ViewType was initialised to view_type.GRID + if(!GridSizeIsSupported(Nav.GridSize)) + { + ToggleView(); + } } } @@ -936,7 +1007,6 @@ InitTraversalStack() } Nav.TraversalStack.push(Level); - console.log(Level); } function @@ -951,6 +1021,13 @@ EmptyElement(Element) while(Element.firstChild) { Element.removeChild(Element.firstChild); } } +function +SetDim(Element, X, Y) +{ + Element.style.width = X; + Element.style.height = Y; +} + function EmptyAndResetButton(Button) { @@ -958,17 +1035,7 @@ EmptyAndResetButton(Button) Button.Element.style.fontSize = null; Button.Element.style.fontWeight = null; - Button.Element.style.width = Nav.ButtonDim + "px"; - Button.Element.style.height = Nav.ButtonDim + "px"; - - for(var i = 0; i < Button.Element.children.length; ++i) - { - Button.Element.children[i].style.fontSize = null; - Button.Element.children[i].style.fontWeight = null; - - Button.Element.children[i].style.width = null; - Button.Element.children[i].style.height = null; - } + SetDim(Button.Element, null, null); for(var i = 0; i < Button.Element.classList.length;) { @@ -1074,8 +1141,11 @@ ComputeItemDistribution(Level) FullButtonEntryCount: 0, }; - // NOTE(matt): Assuming a square grid, reserving the top row for projects - Result.ButtonsForProjects = Math.min(Math.sqrt(Nav.Buttons.length), Result.ProjectsToPlace); + // NOTE(matt): Reserving the top row for projects + if(Result.ProjectsToPlace > 0 && Result.EntriesToPlace > 0) + { + Result.ButtonsForProjects = Math.min(Nav.GridSize.X, Result.ProjectsToPlace); + } Result.ButtonsForEntries = Nav.Buttons.length - Result.ButtonsForProjects; if(Result.EntriesToPlace < Result.ButtonsForEntries) { @@ -1126,8 +1196,6 @@ ResetButtonsContainerClone() ResetTransform(Nav.Transition.Transforms.ButtonsContainerClone.Initial); ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); - Nav.Transition.ButtonsContainerCloneElement.style.width = Nav.ButtonsContainer.style.width; - Nav.Transition.ButtonsContainerCloneElement.style.height = Nav.ButtonsContainer.style.height; Nav.Transition.ButtonsContainerCloneElement.style.gridTemplateColumns = Nav.ButtonsContainer.style.gridTemplateColumns; Nav.Transition.ButtonsContainerCloneElement.style.gridTemplateRows = Nav.ButtonsContainer.style.gridTemplateRows; @@ -1146,6 +1214,7 @@ ResetButtonsContainerClone() Nav.ButtonsContainer.style.zIndex = 1; Nav.ButtonsContainer.style.order = 1; Nav.Transition.ButtonsContainerCloneElement.style.order = 0; + Nav.Transition.ButtonsContainerCloneElement.style.display = "none"; } function @@ -1161,6 +1230,7 @@ CloneButtonsContainer() CopyTransform(Nav.Transition.Transforms.ButtonsContainerClone.Current, Nav.Transition.Transforms.ButtonsContainer.Current); ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); Nav.Transition.ButtonsContainerCloneElement.style.zIndex = 1; + Nav.Transition.ButtonsContainerCloneElement.style.display = "grid"; } function @@ -1556,8 +1626,8 @@ ComputeButtonGeometryRelativeToGrid(Button) var ButtonStyle = window.getComputedStyle(Button); - var GridDimX = Nav.GridWidth; - var GridDimY = Nav.GridWidth; + var GridDimX = Nav.GridDim.X; + var GridDimY = Nav.GridDim.Y; var ButtonDimX = parseInt(ButtonStyle.width); var ButtonDimY = parseInt(ButtonStyle.height); @@ -1620,31 +1690,23 @@ GetTraversalLevelBundle() function FitText(Element) { - if(Element.textContent.includes("Day 068") || Element.textContent.includes("Day 136")) - { - if(Element.textContent.includes("Day 068")) - { - Say("FitText(068)"); - } - else - { - Say("FitText(136)"); - } - var Style = window.getComputedStyle(Element); - Say("Height: " + Style.height); - var ParentStyle = window.getComputedStyle(Element.parentElement); - Say("Parent Height: " + ParentStyle.height); - } + var Paragraph = Element.firstElementChild; + var ParagraphStyle = window.getComputedStyle(Paragraph); + var ElementStyle = window.getComputedStyle(Element); + var Width = parseInt(ElementStyle.width); + var Height = parseInt(ElementStyle.height); Element.style.alignItems = "flex-start"; var FontSize = parseInt(window.getComputedStyle(Element).fontSize); - while(FontSize > 10 && IsOverflowed(Element)) + while(FontSize > 10 && (IsOverflowed(Element) || parseInt(ParagraphStyle.width) > Width || parseInt(ParagraphStyle.height) > Height)) { FontSize -= 0.2; Element.style.fontSize = FontSize + "px"; + ParagraphStyle = window.getComputedStyle(Paragraph); } - if(IsOverflowed(Element)) + ParagraphStyle = window.getComputedStyle(Paragraph); + if(IsOverflowed(Element) || parseInt(ParagraphStyle.width) > Width || parseInt(ParagraphStyle.height) > Height) { Element.style.fontWeight = "normal"; } @@ -1654,16 +1716,21 @@ FitText(Element) function AppendItemToButton(Button, Text, ItemEnd) { + var ButtonElementStyle = window.getComputedStyle(Button.Element); + var VerticalBorderAllowance = parseInt(ButtonElementStyle.borderLeftWidth) + parseInt(ButtonElementStyle.borderRightWidth); + var HorizontalBorderAllowance; var ItemElement = document.createElement("div"); - ItemElement.classList.add("text"); + ItemElement.classList.add("cineraText"); switch(ItemEnd) { case item_end.HEAD: { + HorizonalBorderAllowance = parseInt(ButtonElementStyle.borderTopWidth); ItemElement.classList.add("head-item"); } break; case item_end.TAIL: { + HorizonalBorderAllowance = parseInt(ButtonElementStyle.borderBottomWidth); ItemElement.classList.add("tail-item"); } break; } @@ -1673,527 +1740,537 @@ AppendItemToButton(Button, Text, ItemEnd) ItemElement.style.transform = "rotate3d(0, 0, 1, 180deg)"; } + var ParagraphNode = document.createElement("p"); + ParagraphNode.textContent = Text; + ItemElement.appendChild(ParagraphNode); var Item = Button.Element.appendChild(ItemElement); - Item.textContent = Text; - Item.style.width = Nav.ButtonDim + "px"; - Item.style.height = (Nav.ButtonDim / 2) + "px"; + + // NOTE(matt): This enables Safari to apply height 50% to the head / tail items + var ButtonWidth = parseInt(ButtonElementStyle.width); + var ButtonHeight = parseInt(ButtonElementStyle.height); + SetDim(Button.Element, ButtonWidth + "px", ButtonHeight + "px"); + //// + FitText(Item); } function UpdateButtons(TransitionType, RelevantButton, PoppedLevel) { - var LevelBundle = GetTraversalLevelBundle(); - - Nav.Controls.GridTraversal.Prev.children[0].textContent = "←"; - Nav.Controls.GridTraversal.PrevAscends = false; - Nav.Controls.GridTraversal.NextAscends = false; - if(LevelBundle.Generation <= 1) + if(GridSizeIsSupported(Nav.GridSize)) { - Nav.Controls.GridTraversal.Ascend.classList.add("nowhere"); - Nav.Controls.GridTraversal.Prev.classList.add("nowhere"); - Nav.Controls.GridTraversal.Next.classList.add("nowhere"); - Nav.Controls.GridTraversal.Next.classList.remove("ascension"); - } - else - { - Nav.Controls.GridTraversal.Ascend.classList.remove("nowhere"); - Nav.Controls.GridTraversal.Prev.classList.remove("nowhere"); - Nav.Controls.GridTraversal.Next.classList.remove("nowhere"); + var LevelBundle = GetTraversalLevelBundle(); - if(!HasPrevSibling(LevelBundle.This)) + Nav.Controls.GridTraversal.Prev.children[0].textContent = "←"; + Nav.Controls.GridTraversal.PrevAscends = false; + Nav.Controls.GridTraversal.NextAscends = false; + if(LevelBundle.Generation <= 1) { + Nav.Controls.GridTraversal.Ascend.classList.add("nowhere"); Nav.Controls.GridTraversal.Prev.classList.add("nowhere"); - } - else if(SiblingIsLeaf(siblings.PREV)) - { - Nav.Controls.GridTraversal.PrevAscends = true; - Nav.Controls.GridTraversal.Prev.children[0].textContent = "↰"; - } - - if(!HasNextSibling(LevelBundle.This)) - { Nav.Controls.GridTraversal.Next.classList.add("nowhere"); Nav.Controls.GridTraversal.Next.classList.remove("ascension"); } - else if(SiblingIsLeaf(siblings.NEXT)) - { - Nav.Controls.GridTraversal.NextAscends = true; - Nav.Controls.GridTraversal.Next.classList.add("ascension"); - } else { - Nav.Controls.GridTraversal.Next.classList.remove("ascension"); - } - } + Nav.Controls.GridTraversal.Ascend.classList.remove("nowhere"); + Nav.Controls.GridTraversal.Prev.classList.remove("nowhere"); + Nav.Controls.GridTraversal.Next.classList.remove("nowhere"); - var Distribution = ComputeItemDistribution(LevelBundle.This); - - // NOTE(matt): Centre-alignment. If people would prefer left-alignment, we do that here - // - // We're doing simple 1D centring here, so would need to do correct 2D centring - var HalfEmptyButtonCount = (Nav.Buttons.length - (Distribution.ProjectsToPlace + Distribution.EntriesToPlace)) / 2; - var EmptyPadding = 0; - //EmptyPadding = Math.floor(HalfEmptyButtonCount); // NOTE(matt): Comment out to disable centring - // - - var Prev = null; - var ButtonInfo = { HeadIndex: null, TailIndex: null, ItemCount: null, Theme: null, }; - var DoingEntries = false; - - if(TransitionType !== undefined) - { - CloneButtonsContainer(); - } - - for(var ButtonIndex = 0; ButtonIndex < Nav.Buttons.length; ++ButtonIndex) - { - let This = Nav.Buttons[ButtonIndex]; - EmptyAndResetButton(This); - if(EmptyPadding > 0) - { - --EmptyPadding; - } - else - { - if(Distribution.ProjectsToPlace > 0 || Distribution.EntriesToPlace > 0) + if(!HasPrevSibling(LevelBundle.This)) { - if(Distribution.ProjectsToPlace > 0) - { - This.Projects = LevelBundle.This.Projects; - if(Distribution.ProjectsToPlace == 1 || Distribution.ProjectsToPlace == Distribution.ButtonsForProjects - ButtonIndex) - { - Distribution.FullButtonProjectCount = 1; - } + Nav.Controls.GridTraversal.Prev.classList.add("nowhere"); + } + else if(SiblingIsLeaf(siblings.PREV)) + { + Nav.Controls.GridTraversal.PrevAscends = true; + Nav.Controls.GridTraversal.Prev.children[0].textContent = Nav.SortChronological ? "↰" : "↲"; + } - ButtonInfo = SetButtonInfo(This, Prev, LevelBundle.This, Distribution); - if(ButtonInfo.ItemCount == 1) - { - This.Projects = LevelBundle.This.Projects[ButtonInfo.HeadIndex]; - } - Distribution.ProjectsToPlace -= ButtonInfo.ItemCount; - - if(Distribution.FullButtonProjectCount == 1) - { - This.Element.classList.add("leaf"); - var TextElement = document.createElement("p"); - TextElement.classList.add("text"); - if(!Nav.SortChronological) - { - TextElement.style.transform = "rotate3d(0, 0, 1, 180deg)"; - } - var Text = LevelBundle.This.Projects[ButtonInfo.HeadIndex].querySelector(".cineraProjectTitle").innerText; - var TextNode = document.createTextNode(Text); - TextElement.appendChild(TextNode); - This.Element.appendChild(TextElement); - FitText(This.Element); - } - else - { - var HeadText = LevelBundle.This.Projects[ButtonInfo.HeadIndex].querySelector(".cineraProjectTitle").innerText; - AppendItemToButton(This, HeadText, item_end.HEAD); - - var TailText = LevelBundle.This.Projects[ButtonInfo.TailIndex].querySelector(".cineraProjectTitle").innerText; - AppendItemToButton(This, TailText, item_end.TAIL); - } - } - else - { - This.Entries = LevelBundle.This.Entries; - if(!DoingEntries) - { - Prev = null; - DoingEntries = true; - } - - if(Distribution.EntriesToPlace == 1 || Distribution.EntriesToPlace == Distribution.ButtonsForEntries - ButtonIndex) - { - Distribution.FullButtonEntryCount = 1; - } - - ButtonInfo = SetButtonInfo(This, Prev, LevelBundle.This, Distribution); - if(ButtonInfo.ItemCount == 1) - { - This.Entries = This.Entries[ButtonInfo.HeadIndex]; - } - Distribution.EntriesToPlace -= ButtonInfo.ItemCount; - - if(Distribution.FullButtonEntryCount == 1) - { - This.Element.classList.add("leaf"); - var ButtonLink = document.createElement("a"); - ButtonLink.classList.add("text"); - if(!Nav.SortChronological) - { - ButtonLink.style.transform = "rotate3d(0, 0, 1, 180deg)"; - } - var EntryAddress = LevelBundle.This.Entries[ButtonInfo.HeadIndex].lastElementChild.getAttribute("href"); - ButtonLink.setAttribute("href", EntryAddress); - var Text = LevelBundle.This.Entries[ButtonInfo.HeadIndex].innerText; - var TextNode = document.createTextNode(Text); - ButtonLink.appendChild(TextNode); - - This.Element.appendChild(ButtonLink); - FitText(This.Element); - } - else - { - var HeadText = LevelBundle.This.Entries[ButtonInfo.HeadIndex].innerText; - AppendItemToButton(This, HeadText, item_end.HEAD); - - var TailText = LevelBundle.This.Entries[ButtonInfo.TailIndex].innerText; - AppendItemToButton(This, TailText, item_end.TAIL); - } - } - - This.Element.classList.add(ButtonInfo.Theme); - Prev = ButtonInfo; + if(!HasNextSibling(LevelBundle.This)) + { + Nav.Controls.GridTraversal.Next.classList.add("nowhere"); + Nav.Controls.GridTraversal.Next.classList.remove("ascension"); + } + else if(SiblingIsLeaf(siblings.NEXT)) + { + Nav.Controls.GridTraversal.NextAscends = true; + Nav.Controls.GridTraversal.Next.classList.add("ascension"); } else { - This.Element.classList.add(Nav.Nexus.classList[0]); + Nav.Controls.GridTraversal.Next.classList.remove("ascension"); } } - if(PoppedLevel && !Nav.Transition.RelevantButtonElement && ButtonAndLevelMatch(This, PoppedLevel)) + + var Distribution = ComputeItemDistribution(LevelBundle.This); + + // NOTE(matt): Centre-alignment. If people would prefer left-alignment, we do that here + // + // We're doing simple 1D centring here, so would need to do correct 2D centring + var HalfEmptyButtonCount = (Nav.Buttons.length - (Distribution.ProjectsToPlace + Distribution.EntriesToPlace)) / 2; + var EmptyPadding = 0; + //EmptyPadding = Math.floor(HalfEmptyButtonCount); // NOTE(matt): Comment out to disable centring + // + + var Prev = null; + var ButtonInfo = { HeadIndex: null, TailIndex: null, ItemCount: null, Theme: null, }; + var DoingEntries = false; + + if(TransitionType !== undefined) { - Nav.Transition.RelevantButtonElement = This.Element; + CloneButtonsContainer(); } - } - if(TransitionType !== undefined) - { - switch(TransitionType) + + for(var ButtonIndex = 0; ButtonIndex < Nav.Buttons.length; ++ButtonIndex) { - case transition_type.SIBLING_SHIFT_PREV: + let This = Nav.Buttons[ButtonIndex]; + EmptyAndResetButton(This); + if(EmptyPadding > 0) + { + --EmptyPadding; + } + else + { + if(Distribution.ProjectsToPlace > 0 || Distribution.EntriesToPlace > 0) { - // Init targets - //// ButtonsTransitionContainer - let TargetA0 = NullTarget(); - var Padding = Nav.GridColumnGap; - if(Nav.SortChronological) + if(Distribution.ProjectsToPlace > 0) { - TargetA0.ScrollX = 0; + This.Projects = LevelBundle.This.Projects; + if(Distribution.ProjectsToPlace == 1 || Distribution.ProjectsToPlace == Distribution.ButtonsForProjects - ButtonIndex) + { + Distribution.FullButtonProjectCount = 1; + } + + ButtonInfo = SetButtonInfo(This, Prev, LevelBundle.This, Distribution); + if(ButtonInfo.ItemCount == 1) + { + This.Projects = LevelBundle.This.Projects[ButtonInfo.HeadIndex]; + } + Distribution.ProjectsToPlace -= ButtonInfo.ItemCount; + + if(Distribution.FullButtonProjectCount == 1) + { + This.Element.classList.add("leaf"); + var TextElement = document.createElement("p"); + TextElement.classList.add("cineraText"); + if(!Nav.SortChronological) + { + TextElement.style.transform = "rotate3d(0, 0, 1, 180deg)"; + } + var Text = LevelBundle.This.Projects[ButtonInfo.HeadIndex].querySelector(".cineraProjectTitle").innerText; + var TextNode = document.createTextNode(Text); + TextElement.appendChild(TextNode); + This.Element.appendChild(TextElement); + FitText(This.Element); + } + else + { + var HeadText = LevelBundle.This.Projects[ButtonInfo.HeadIndex].querySelector(".cineraProjectTitle").innerText; + AppendItemToButton(This, HeadText, item_end.HEAD); + + var TailText = LevelBundle.This.Projects[ButtonInfo.TailIndex].querySelector(".cineraProjectTitle").innerText; + AppendItemToButton(This, TailText, item_end.TAIL); + } } else { - TargetA0.ScrollX = Nav.GridWidth + Padding; + This.Entries = LevelBundle.This.Entries; + if(!DoingEntries) + { + Prev = null; + DoingEntries = true; + } + + if(Distribution.EntriesToPlace == 1 || Distribution.EntriesToPlace == Distribution.ButtonsForEntries - ButtonIndex) + { + Distribution.FullButtonEntryCount = 1; + } + + ButtonInfo = SetButtonInfo(This, Prev, LevelBundle.This, Distribution); + if(ButtonInfo.ItemCount == 1) + { + This.Entries = This.Entries[ButtonInfo.HeadIndex]; + } + Distribution.EntriesToPlace -= ButtonInfo.ItemCount; + + if(Distribution.FullButtonEntryCount == 1) + { + This.Element.classList.add("leaf"); + var ButtonLink = document.createElement("a"); + ButtonLink.classList.add("cineraText"); + if(!Nav.SortChronological) + { + ButtonLink.style.transform = "rotate3d(0, 0, 1, 180deg)"; + } + var EntryAddress = LevelBundle.This.Entries[ButtonInfo.HeadIndex].lastElementChild.getAttribute("href"); + ButtonLink.setAttribute("href", EntryAddress); + var Text = LevelBundle.This.Entries[ButtonInfo.HeadIndex].innerText; + var TextNode = document.createTextNode(Text); + ButtonLink.appendChild(TextNode); + + This.Element.appendChild(ButtonLink); + FitText(This.Element); + } + else + { + var HeadText = LevelBundle.This.Entries[ButtonInfo.HeadIndex].innerText; + AppendItemToButton(This, HeadText, item_end.HEAD); + + var TailText = LevelBundle.This.Entries[ButtonInfo.TailIndex].innerText; + AppendItemToButton(This, TailText, item_end.TAIL); + } } - Nav.Transition.StageDurations.push(320); - Nav.Transition.Transforms.ButtonsTransitionContainer.TargetStages.push(TargetA0); - - // Prep - Nav.Transition.ButtonsContainerCloneElement.style.position = "relative"; - - var ScrollX; - if(Nav.SortChronological) - { - Nav.ButtonsContainer.style.order = 0; - Nav.Transition.ButtonsContainerCloneElement.style.order = 1; - ScrollX = Nav.GridWidth + Padding; - } - else - { - Nav.ButtonsContainer.style.order = 1; - Nav.Transition.ButtonsContainerCloneElement.style.order = 0; - ScrollX = 0; - } - - Nav.Transition.ButtonsContainerCloneElement.style.paddingLeft = Padding + "px"; - - Nav.Transition.Transforms.ButtonsTransitionContainer.Current.ScrollX = ScrollX; - ApplyTransform(Nav.Transition.ButtonsTransitionContainerElement, Nav.Transition.Transforms.ButtonsTransitionContainer.Current); - } break; - case transition_type.SIBLING_SHIFT_NEXT: + This.Element.classList.add(ButtonInfo.Theme); + Prev = ButtonInfo; + } + else { - // Init targets - //// - let TargetA0 = NullTarget(); - var Padding = Nav.GridColumnGap; - if(Nav.SortChronological) - { - TargetA0.ScrollX = Nav.GridWidth + Padding; - } - else - { - TargetA0.ScrollX = 0; - } - - Nav.Transition.StageDurations.push(320); - Nav.Transition.Transforms.ButtonsTransitionContainer.TargetStages.push(TargetA0); - - // Prep - Nav.Transition.ButtonsContainerCloneElement.style.position = "relative"; - - var ScrollX; - - if(Nav.SortChronological) - { - Nav.ButtonsContainer.style.order = 1; - Nav.Transition.ButtonsContainerCloneElement.style.order = 0; - ScrollX = 0; - } - else - { - Nav.ButtonsContainer.style.order = 0; - Nav.Transition.ButtonsContainerCloneElement.style.order = 1; - ScrollX = Nav.GridWidth + Padding; - } - - Nav.Transition.ButtonsContainerCloneElement.style.paddingRight = Padding + "px"; - - Nav.Transition.Transforms.ButtonsTransitionContainer.Current.ScrollX = ScrollX; - ApplyTransform(Nav.Transition.ButtonsTransitionContainerElement, Nav.Transition.Transforms.ButtonsTransitionContainer.Current); - } break; - case transition_type.PROJECT_ENTRY: - { - // Init targets - //// ButtonsContainer - let TargetA0 = NullTarget(); - let TargetA1 = NullTarget(); - let TargetA2 = NullTarget(); - let TargetA3 = NullTarget(); - - if(Nav.SortChronological) - { - TargetA0.Rotation.Y = 90; - } - else - { - TargetA0.Rotation.Y = -90; - } - TargetA1.ZIndex = 1; - TargetA2.Rotation.Y = 0; - TargetA3.Pos.X = 0; - TargetA3.Pos.Y = 0; - TargetA3.Scale.X = 1; - TargetA3.Scale.Y = 1; - - //// RelevantButton - let TargetB0 = NullTarget(); - let TargetB1 = NullTarget(); - let TargetB2 = NullTarget(); - - if(Nav.SortChronological) - { - TargetB0.Rotation.Y = -90; - TargetB2.Rotation.Y = -180; - } - else - { - TargetB0.Rotation.Y = 90; - TargetB2.Rotation.Y = 180; - } - - //// ButtonsContainerClone - let TargetC0 = NullTarget(); - let TargetC1 = NullTarget(); - - TargetC1.ZIndex = 0; - - - Nav.Transition.StageDurations.push(80); - Nav.Transition.StageDurations.push(0); - Nav.Transition.StageDurations.push(80); - Nav.Transition.StageDurations.push(160); - - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA2); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA3); - Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB0); - Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB1); - Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB2); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC0); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC1); - - // Prep - var RelevantButtonIndex = GetIndexOfButton(RelevantButton); - Nav.Transition.RelevantButtonElement = Nav.Transition.ButtonsContainerCloneElement.children[RelevantButtonIndex]; - - var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); - - Nav.Transition.Transforms.ButtonsContainer.Current.Pos.X = ButtonGeometry.Pos.X; - Nav.Transition.Transforms.ButtonsContainer.Current.Pos.Y = ButtonGeometry.Pos.Y; - Nav.Transition.Transforms.ButtonsContainer.Current.Scale.X = ButtonGeometry.Scale.X; - Nav.Transition.Transforms.ButtonsContainer.Current.Scale.Y = ButtonGeometry.Scale.Y; - if(Nav.SortChronological) - { - Nav.Transition.Transforms.ButtonsContainer.Current.Rotation.Y = 180; - } - else - { - Nav.Transition.Transforms.ButtonsContainer.Current.Rotation.Y = -180; - } - - Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 0; - - Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 1; - - ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); - ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); - } break; - case transition_type.PROJECT_EXIT: - { - // Init targets - //// ButtonsContainer - let TargetA0 = NullTarget(); - let TargetA1 = NullTarget(); - let TargetA2 = NullTarget(); - TargetA2.ZIndex = 1; - - //// RelevantButton - let TargetB0 = NullTarget(); - let TargetB1 = NullTarget(); - let TargetB2 = NullTarget(); - let TargetB3 = NullTarget(); - - if(Nav.SortChronological) - { - TargetB1.Rotation.Y = -90; - } - else - { - TargetB1.Rotation.Y = 90; - } - TargetB3.Rotation.Y = 0; - - //// ButtonsContainerClone - let TargetC0 = NullTarget(); - let TargetC1 = NullTarget(); - let TargetC2 = NullTarget(); - let TargetC3 = NullTarget(); - - var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); - TargetC0.Pos.X = ButtonGeometry.Pos.X; - TargetC0.Pos.Y = ButtonGeometry.Pos.Y; - TargetC0.Scale.X = ButtonGeometry.Scale.X; - TargetC0.Scale.Y = ButtonGeometry.Scale.Y; - if(Nav.SortChronological) - { - TargetC1.Rotation.Y = 90; - TargetC3.Rotation.Y = 180; - } - else - { - TargetC1.Rotation.Y = -90; - TargetC3.Rotation.Y = -180; - } - TargetC2.ZIndex = 0; - - - Nav.Transition.StageDurations.push(160); - Nav.Transition.StageDurations.push(80); - Nav.Transition.StageDurations.push(0); - Nav.Transition.StageDurations.push(80); - - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA2); - Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB0); - Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB1); - Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB2); - Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB3); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC0); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC1); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC2); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC3); - - // Prep - if(Nav.SortChronological) - { - Nav.Transition.Transforms.RelevantButton.Current.Rotation.Y = -180; - } - else - { - Nav.Transition.Transforms.RelevantButton.Current.Rotation.Y = 180; - } - ApplyTransform(Nav.Transition.RelevantButtonElement, Nav.Transition.Transforms.RelevantButton.Current); - - Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 0; - ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); - - Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 1; - ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); - } break; - case transition_type.SUBDIVISION_DESCENT: - { - // Init targets - //// ButtonsContainer - let TargetA0 = NullTarget(); - let TargetA1 = NullTarget(); - - TargetA0.Opacity = 1; - TargetA1.Pos.X = 0; - TargetA1.Pos.Y = 0; - TargetA1.Scale.X = 1; - TargetA1.Scale.Y = 1; - - Nav.Transition.StageDurations.push(160); - Nav.Transition.StageDurations.push(160); - - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); - - // Prep - var RelevantButtonIndex = GetIndexOfButton(RelevantButton); - Nav.Transition.RelevantButtonElement = Nav.Transition.ButtonsContainerCloneElement.children[RelevantButtonIndex]; - - var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); - - Nav.Transition.Transforms.ButtonsContainer.Current.Pos.X = ButtonGeometry.Pos.X; - Nav.Transition.Transforms.ButtonsContainer.Current.Pos.Y = ButtonGeometry.Pos.Y; - Nav.Transition.Transforms.ButtonsContainer.Current.Scale.X = ButtonGeometry.Scale.X; - Nav.Transition.Transforms.ButtonsContainer.Current.Scale.Y = ButtonGeometry.Scale.Y; - Nav.Transition.Transforms.ButtonsContainer.Current.Opacity = 0; - Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 1; - - Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 0; - - ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); - ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); - } break; - case transition_type.SUBDIVISION_ASCENT: - { - // Init targets - //// ButtonsContainer - let TargetA0 = NullTarget(); - let TargetA1 = NullTarget(); - let TargetA2 = NullTarget(); - TargetA2.ZIndex = 1; - - //// ButtonsContainerClone - let TargetC0 = NullTarget(); - let TargetC1 = NullTarget(); - let TargetC2 = NullTarget(); - - var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); - TargetC0.Pos.X = ButtonGeometry.Pos.X; - TargetC0.Pos.Y = ButtonGeometry.Pos.Y; - TargetC0.Scale.X = ButtonGeometry.Scale.X; - TargetC0.Scale.Y = ButtonGeometry.Scale.Y; - TargetC1.Opacity = 0; - TargetC2.ZIndex = 0; - - - Nav.Transition.StageDurations.push(160); - Nav.Transition.StageDurations.push(160); - Nav.Transition.StageDurations.push(0); - - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); - Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA2); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC0); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC1); - Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC2); - - // Prep - Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 0; - Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 1; - ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); - ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); - } break; + This.Element.classList.add(Nav.Nexus.classList[0]); + } + } + if(PoppedLevel && !Nav.Transition.RelevantButtonElement && ButtonAndLevelMatch(This, PoppedLevel)) + { + Nav.Transition.RelevantButtonElement = This.Element; + } + } + if(TransitionType !== undefined) + { + switch(TransitionType) + { + case transition_type.SIBLING_SHIFT_PREV: + { + // Init targets + //// ButtonsTransitionContainer + let TargetA0 = NullTarget(); + var Padding = Nav.GridColumnGap; + if(Nav.SortChronological) + { + TargetA0.ScrollX = 0; + } + else + { + TargetA0.ScrollX = Nav.GridDim.X + Padding; + } + + Nav.Transition.StageDurations.push(320); + Nav.Transition.Transforms.ButtonsTransitionContainer.TargetStages.push(TargetA0); + + // Prep + Nav.Transition.ButtonsContainerCloneElement.style.position = "relative"; + + var ScrollX; + if(Nav.SortChronological) + { + Nav.ButtonsContainer.style.order = 0; + Nav.Transition.ButtonsContainerCloneElement.style.order = 1; + ScrollX = Nav.GridDim.X + Padding; + } + else + { + Nav.ButtonsContainer.style.order = 1; + Nav.Transition.ButtonsContainerCloneElement.style.order = 0; + ScrollX = 0; + } + + Nav.Transition.ButtonsContainerCloneElement.style.paddingLeft = Padding + "px"; + + Nav.Transition.Transforms.ButtonsTransitionContainer.Current.ScrollX = ScrollX; + ApplyTransform(Nav.Transition.ButtonsTransitionContainerElement, Nav.Transition.Transforms.ButtonsTransitionContainer.Current); + } break; + case transition_type.SIBLING_SHIFT_NEXT: + { + // Init targets + //// + let TargetA0 = NullTarget(); + var Padding = Nav.GridColumnGap; + if(Nav.SortChronological) + { + TargetA0.ScrollX = Nav.GridDim.X + Padding; + } + else + { + TargetA0.ScrollX = 0; + } + + Nav.Transition.StageDurations.push(320); + Nav.Transition.Transforms.ButtonsTransitionContainer.TargetStages.push(TargetA0); + + // Prep + Nav.Transition.ButtonsContainerCloneElement.style.position = "relative"; + + var ScrollX; + + if(Nav.SortChronological) + { + Nav.ButtonsContainer.style.order = 1; + Nav.Transition.ButtonsContainerCloneElement.style.order = 0; + ScrollX = 0; + } + else + { + Nav.ButtonsContainer.style.order = 0; + Nav.Transition.ButtonsContainerCloneElement.style.order = 1; + ScrollX = Nav.GridDim.X + Padding; + } + + Nav.Transition.ButtonsContainerCloneElement.style.paddingRight = Padding + "px"; + + Nav.Transition.Transforms.ButtonsTransitionContainer.Current.ScrollX = ScrollX; + ApplyTransform(Nav.Transition.ButtonsTransitionContainerElement, Nav.Transition.Transforms.ButtonsTransitionContainer.Current); + } break; + case transition_type.PROJECT_ENTRY: + { + // Init targets + //// ButtonsContainer + let TargetA0 = NullTarget(); + let TargetA1 = NullTarget(); + let TargetA2 = NullTarget(); + let TargetA3 = NullTarget(); + + if(Nav.SortChronological) + { + TargetA0.Rotation.Y = 90; + } + else + { + TargetA0.Rotation.Y = -90; + } + TargetA1.ZIndex = 1; + TargetA2.Rotation.Y = 0; + TargetA3.Pos.X = 0; + TargetA3.Pos.Y = 0; + TargetA3.Scale.X = 1; + TargetA3.Scale.Y = 1; + + //// RelevantButton + let TargetB0 = NullTarget(); + let TargetB1 = NullTarget(); + let TargetB2 = NullTarget(); + + if(Nav.SortChronological) + { + TargetB0.Rotation.Y = -90; + TargetB2.Rotation.Y = -180; + } + else + { + TargetB0.Rotation.Y = 90; + TargetB2.Rotation.Y = 180; + } + + //// ButtonsContainerClone + let TargetC0 = NullTarget(); + let TargetC1 = NullTarget(); + + TargetC1.ZIndex = 0; + + + Nav.Transition.StageDurations.push(80); + Nav.Transition.StageDurations.push(0); + Nav.Transition.StageDurations.push(80); + Nav.Transition.StageDurations.push(160); + + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA2); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA3); + Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB0); + Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB1); + Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB2); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC0); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC1); + + // Prep + var RelevantButtonIndex = GetIndexOfButton(RelevantButton); + Nav.Transition.RelevantButtonElement = Nav.Transition.ButtonsContainerCloneElement.children[RelevantButtonIndex]; + + var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); + + Nav.Transition.Transforms.ButtonsContainer.Current.Pos.X = ButtonGeometry.Pos.X; + Nav.Transition.Transforms.ButtonsContainer.Current.Pos.Y = ButtonGeometry.Pos.Y; + Nav.Transition.Transforms.ButtonsContainer.Current.Scale.X = ButtonGeometry.Scale.X; + Nav.Transition.Transforms.ButtonsContainer.Current.Scale.Y = ButtonGeometry.Scale.Y; + if(Nav.SortChronological) + { + Nav.Transition.Transforms.ButtonsContainer.Current.Rotation.Y = 180; + } + else + { + Nav.Transition.Transforms.ButtonsContainer.Current.Rotation.Y = -180; + } + + Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 0; + + Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 1; + + ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); + ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); + } break; + case transition_type.PROJECT_EXIT: + { + // Init targets + //// ButtonsContainer + let TargetA0 = NullTarget(); + let TargetA1 = NullTarget(); + let TargetA2 = NullTarget(); + TargetA2.ZIndex = 1; + + //// RelevantButton + let TargetB0 = NullTarget(); + let TargetB1 = NullTarget(); + let TargetB2 = NullTarget(); + let TargetB3 = NullTarget(); + + if(Nav.SortChronological) + { + TargetB1.Rotation.Y = -90; + } + else + { + TargetB1.Rotation.Y = 90; + } + TargetB3.Rotation.Y = 0; + + //// ButtonsContainerClone + let TargetC0 = NullTarget(); + let TargetC1 = NullTarget(); + let TargetC2 = NullTarget(); + let TargetC3 = NullTarget(); + + var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); + TargetC0.Pos.X = ButtonGeometry.Pos.X; + TargetC0.Pos.Y = ButtonGeometry.Pos.Y; + TargetC0.Scale.X = ButtonGeometry.Scale.X; + TargetC0.Scale.Y = ButtonGeometry.Scale.Y; + if(Nav.SortChronological) + { + TargetC1.Rotation.Y = 90; + TargetC3.Rotation.Y = 180; + } + else + { + TargetC1.Rotation.Y = -90; + TargetC3.Rotation.Y = -180; + } + TargetC2.ZIndex = 0; + + + Nav.Transition.StageDurations.push(160); + Nav.Transition.StageDurations.push(80); + Nav.Transition.StageDurations.push(0); + Nav.Transition.StageDurations.push(80); + + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA2); + Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB0); + Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB1); + Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB2); + Nav.Transition.Transforms.RelevantButton.TargetStages.push(TargetB3); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC0); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC1); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC2); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC3); + + // Prep + if(Nav.SortChronological) + { + Nav.Transition.Transforms.RelevantButton.Current.Rotation.Y = -180; + } + else + { + Nav.Transition.Transforms.RelevantButton.Current.Rotation.Y = 180; + } + ApplyTransform(Nav.Transition.RelevantButtonElement, Nav.Transition.Transforms.RelevantButton.Current); + + Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 0; + ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); + + Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 1; + ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); + } break; + case transition_type.SUBDIVISION_DESCENT: + { + // Init targets + //// ButtonsContainer + let TargetA0 = NullTarget(); + let TargetA1 = NullTarget(); + + TargetA0.Opacity = 1; + TargetA1.Pos.X = 0; + TargetA1.Pos.Y = 0; + TargetA1.Scale.X = 1; + TargetA1.Scale.Y = 1; + + Nav.Transition.StageDurations.push(160); + Nav.Transition.StageDurations.push(160); + + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); + + // Prep + var RelevantButtonIndex = GetIndexOfButton(RelevantButton); + Nav.Transition.RelevantButtonElement = Nav.Transition.ButtonsContainerCloneElement.children[RelevantButtonIndex]; + + var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); + + Nav.Transition.Transforms.ButtonsContainer.Current.Pos.X = ButtonGeometry.Pos.X; + Nav.Transition.Transforms.ButtonsContainer.Current.Pos.Y = ButtonGeometry.Pos.Y; + Nav.Transition.Transforms.ButtonsContainer.Current.Scale.X = ButtonGeometry.Scale.X; + Nav.Transition.Transforms.ButtonsContainer.Current.Scale.Y = ButtonGeometry.Scale.Y; + Nav.Transition.Transforms.ButtonsContainer.Current.Opacity = 0; + Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 1; + + Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 0; + + ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); + ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); + } break; + case transition_type.SUBDIVISION_ASCENT: + { + // Init targets + //// ButtonsContainer + let TargetA0 = NullTarget(); + let TargetA1 = NullTarget(); + let TargetA2 = NullTarget(); + TargetA2.ZIndex = 1; + + //// ButtonsContainerClone + let TargetC0 = NullTarget(); + let TargetC1 = NullTarget(); + let TargetC2 = NullTarget(); + + var ButtonGeometry = ComputeButtonGeometryRelativeToGrid(Nav.Transition.RelevantButtonElement); + TargetC0.Pos.X = ButtonGeometry.Pos.X; + TargetC0.Pos.Y = ButtonGeometry.Pos.Y; + TargetC0.Scale.X = ButtonGeometry.Scale.X; + TargetC0.Scale.Y = ButtonGeometry.Scale.Y; + TargetC1.Opacity = 0; + TargetC2.ZIndex = 0; + + + Nav.Transition.StageDurations.push(160); + Nav.Transition.StageDurations.push(160); + Nav.Transition.StageDurations.push(0); + + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA0); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA1); + Nav.Transition.Transforms.ButtonsContainer.TargetStages.push(TargetA2); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC0); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC1); + Nav.Transition.Transforms.ButtonsContainerClone.TargetStages.push(TargetC2); + + // Prep + Nav.Transition.Transforms.ButtonsContainer.Current.ZIndex = 0; + Nav.Transition.Transforms.ButtonsContainerClone.Current.ZIndex = 1; + ApplyTransform(Nav.Transition.ButtonsContainerCloneElement, Nav.Transition.Transforms.ButtonsContainerClone.Current); + ApplyTransform(Nav.ButtonsContainer, Nav.Transition.Transforms.ButtonsContainer.Current); + } break; + } + DoTransition(); } - DoTransition(); } } @@ -2438,7 +2515,7 @@ ShouldFireGridEvents() } function -ModifyButtonKeybinding(Event) +ModifyControlKeybinding(Event) { // TODO(matt): Settle on the final sets of bindings var Chron = Nav.SortChronological; @@ -2456,79 +2533,102 @@ ModifyButtonKeybinding(Event) case "k": if(ShouldFireGridEvents()) { EnqueueInteraction(interaction_type.ASCEND); } break; case "l": if(ShouldFireGridEvents()) { EnqueueInteraction(Chron ? interaction_type.SIBLING_SHIFT_NEXT : interaction_type.SIBLING_SHIFT_PREV); } break; } +} - if(Nav.GridSize == 2) +function +BindControlKeys() +{ + document.addEventListener("keydown", ModifyControlKeybinding); +} + +function +UnbindControlKeys() +{ + document.removeEventListener("keydown", ModifyControlKeybinding); +} + +function +RebindControlKeys() +{ + UnbindControlKeys(); + BindControlKeys(); +} + +function +KeyIsInGrid(GridSize, KeyPos) +{ + return GridSize.X > KeyPos.X && GridSize.Y > KeyPos.Y; +} + +function +ComputeNaturalKeyIndex(GridSize, KeyPos) +{ + return KeyPos.Y * GridSize.X + KeyPos.X; +} + +function +EnqueueGridInteraction(GridSize, KeyPos) +{ + var Chron = Nav.SortChronological; + var LastButtonIndex = Nav.Buttons.length - 1; + var NaturalIndex = ComputeNaturalKeyIndex(GridSize, KeyPos); + var IT = interaction_type.PUSH_BUTTON; + var ID = { Element: null, Button: null, }; // NOTE(matt): InteractionData + ID.Element = Nav.Buttons[Chron ? NaturalIndex : LastButtonIndex - NaturalIndex].Element; + ID.Button = Nav.Buttons[Chron ? NaturalIndex : LastButtonIndex - NaturalIndex]; + EnqueueInteraction(IT, ID); +} + +function +Get2DPosFromIndex(Layout, Index) +{ + var Result = { + X: null, + Y: null, + }; + + Result.X = Index % Layout.X; + Result.Y = (Index - Result.X) / Layout.Y; + + return Result; +} + +function +ModifyGridKeybinding(Event) +{ + var Key = Event.key; + // TODO(matt): With this, we could probably easily add a setting for keyboard layout: e.g. Dvorak + var PhysicalKeys = [ + "1", "2", "3", "4", + "q", "w", "e", "r", + "a", "s", "d", "f", + "z", "x", "c", "v" + ]; + + var KeyLayout = { X: 4, Y: 4 }; + for(var i = 0; i < PhysicalKeys.length; ++i) { - switch(Key) + if(Key == PhysicalKeys[i]) { - case "1": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 0 : 3].Element; ID.Button = Nav.Buttons[Chron ? 0 : 3]; EnqueueInteraction(IT, ID); } break; - case "2": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 1 : 2].Element; ID.Button = Nav.Buttons[Chron ? 1 : 2]; EnqueueInteraction(IT, ID); } break; - - case "q": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 2 : 1].Element; ID.Button = Nav.Buttons[Chron ? 2 : 1]; EnqueueInteraction(IT, ID); } break; - case "w": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 3 : 0].Element; ID.Button = Nav.Buttons[Chron ? 3 : 0]; EnqueueInteraction(IT, ID); } break; - } - } - else if(Nav.GridSize == 3) - { - switch(Key) - { - case "1": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 0 : 8].Element; ID.Button = Nav.Buttons[Chron ? 0 : 8]; EnqueueInteraction(IT, ID); } break; - case "2": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 1 : 7].Element; ID.Button = Nav.Buttons[Chron ? 1 : 7]; EnqueueInteraction(IT, ID); } break; - case "3": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 2 : 6].Element; ID.Button = Nav.Buttons[Chron ? 2 : 6]; EnqueueInteraction(IT, ID); } break; - - case "q": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 3 : 5].Element; ID.Button = Nav.Buttons[Chron ? 3 : 5]; EnqueueInteraction(IT, ID); } break; - case "w": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 4 : 4].Element; ID.Button = Nav.Buttons[Chron ? 4 : 4]; EnqueueInteraction(IT, ID); } break; - case "e": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 5 : 3].Element; ID.Button = Nav.Buttons[Chron ? 5 : 3]; EnqueueInteraction(IT, ID); } break; - - case "a": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 6 : 2].Element; ID.Button = Nav.Buttons[Chron ? 6 : 2]; EnqueueInteraction(IT, ID); } break; - case "s": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 7 : 1].Element; ID.Button = Nav.Buttons[Chron ? 7 : 1]; EnqueueInteraction(IT, ID); } break; - case "d": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 8 : 0].Element; ID.Button = Nav.Buttons[Chron ? 8 : 0]; EnqueueInteraction(IT, ID); } break; - } - } - else if(Nav.GridSize == 4) - { - switch(Key) - { - case "1": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 0 : 15].Element; ID.Button = Nav.Buttons[Chron ? 0 : 15]; EnqueueInteraction(IT, ID); } break; - case "2": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 1 : 14].Element; ID.Button = Nav.Buttons[Chron ? 1 : 14]; EnqueueInteraction(IT, ID); } break; - case "3": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 2 : 13].Element; ID.Button = Nav.Buttons[Chron ? 2 : 13]; EnqueueInteraction(IT, ID); } break; - case "4": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 3 : 12].Element; ID.Button = Nav.Buttons[Chron ? 3 : 12]; EnqueueInteraction(IT, ID); } break; - - case "q": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 4 : 11].Element; ID.Button = Nav.Buttons[Chron ? 4 : 11]; EnqueueInteraction(IT, ID); } break; - case "w": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 5 : 10].Element; ID.Button = Nav.Buttons[Chron ? 5 : 10]; EnqueueInteraction(IT, ID); } break; - case "e": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 6 : 9].Element; ID.Button = Nav.Buttons[Chron ? 6 : 9]; EnqueueInteraction(IT, ID); } break; - case "r": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 7 : 8].Element; ID.Button = Nav.Buttons[Chron ? 7 : 8]; EnqueueInteraction(IT, ID); } break; - - case "a": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 8 : 7].Element; ID.Button = Nav.Buttons[Chron ? 8 : 7]; EnqueueInteraction(IT, ID); } break; - case "s": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 9 : 6].Element; ID.Button = Nav.Buttons[Chron ? 9 : 6]; EnqueueInteraction(IT, ID); } break; - case "d": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 10 : 5].Element; ID.Button = Nav.Buttons[Chron ? 10 : 5]; EnqueueInteraction(IT, ID); } break; - case "f": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 11 : 4].Element; ID.Button = Nav.Buttons[Chron ? 11 : 4]; EnqueueInteraction(IT, ID); } break; - - case "z": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 12 : 3].Element; ID.Button = Nav.Buttons[Chron ? 12 : 3]; EnqueueInteraction(IT, ID); } break; - case "x": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 13 : 2].Element; ID.Button = Nav.Buttons[Chron ? 13 : 2]; EnqueueInteraction(IT, ID); } break; - case "c": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 14 : 1].Element; ID.Button = Nav.Buttons[Chron ? 14 : 1]; EnqueueInteraction(IT, ID); } break; - case "v": if(ShouldFireGridEvents()) { ID.Element = Nav.Buttons[Chron ? 15 : 0].Element; ID.Button = Nav.Buttons[Chron ? 15 : 0]; EnqueueInteraction(IT, ID); } break; + var KeyPos = Get2DPosFromIndex(KeyLayout, i); + if(KeyIsInGrid(Nav.GridSize, KeyPos) && ShouldFireGridEvents()) + { + EnqueueGridInteraction(Nav.GridSize, KeyPos); + } } } } function -BindKeys() +BindGridKeys() { - document.addEventListener("keydown", ModifyButtonKeybinding); + document.addEventListener("keydown", ModifyGridKeybinding); } function -UnbindKeys() +UnbindGridKeys() { - document.removeEventListener("keydown", ModifyButtonKeybinding); -} - -function -RebindKeys() -{ - UnbindKeys(); - BindKeys(); + document.removeEventListener("keydown", ModifyGridKeybinding); } function @@ -2564,7 +2664,7 @@ DoRotationStage(Now) for(var i = 0; i < Nav.ButtonsContainer.children.length; ++i) { var This = Nav.ButtonsContainer.children[i]; - var ThisTexts = This.querySelectorAll(".text"); + var ThisTexts = This.querySelectorAll(".cineraText"); for(var j = 0; j < ThisTexts.length; ++j) { ThisTexts[j].style.transform = "rotate3d(0, 0, 1, " + -Nav.Transition.Transforms.ButtonsContainer.Current.Rotation.Z + "deg)"; @@ -2589,7 +2689,7 @@ DoRotationStage(Now) function RotateButtons(Initialising) { - // TODO(matt): Consider pushing this through DoTransition(), aware that it'd need to transform ".text" children + // TODO(matt): Consider pushing this through DoTransition(), aware that it'd need to transform ".cineraText" children CopyTransform(Nav.Transition.Transforms.ButtonsContainer.Initial, Nav.Transition.Transforms.ButtonsContainer.Current); Nav.Transition.StartTime = undefined; if(!Initialising && Nav.Transition.Enabled) @@ -2654,15 +2754,27 @@ Sort(Initialising) } if(Initialising && Nav.Transition.Enabled) { setTimeout(AddAnimationClass, 320); } - UnbindKeys(); + UnbindGridKeys(Nav.GridSize); Nav.SortChronological = !Nav.SortChronological; + if(Nav.Controls.GridTraversal.PrevAscends) + { + if(Nav.SortChronological) + { + Nav.Controls.GridTraversal.Prev.children[0].textContent = "↰"; + } + else + { + Nav.Controls.GridTraversal.Prev.children[0].textContent = "↲"; + } + } + if(MaintainingState()) { if(Nav.SortChronological) { ClearStateBit(state_bit.SORT_REVERSED); } else { SetStateBit(state_bit.SORT_REVERSED); } } RotateButtons(Initialising); - RebindKeys(); + BindGridKeys(); runSearch(true); } @@ -2715,6 +2827,29 @@ EnqueueInteraction(InteractionType, Data) } } +function +UseOrientation(Orientation) +{ + Nav.GridContainer.classList.remove("Portrait", "Landscape", "Left", "Right"); + switch(Orientation) + { + case orientations.PORTRAIT: + { + Nav.GridContainer.classList.add("Portrait"); + } break; + + case orientations.LANDSCAPE_LEFT: + { + Nav.GridContainer.classList.add("Landscape", "Left"); + } break; + + case orientations.LANDSCAPE_RIGHT: + { + Nav.GridContainer.classList.add("Landscape", "Right"); + } break; + } +} + function InitNexus() { @@ -2749,91 +2884,151 @@ InitNexus() ScrollCondition = true; // NOTE(matt): Variable in cinera_pre.js, we init with the Grid which is the view we want to auto-scroll if(CineraProps.IsMobile) { - switch(CineraProps.Orientation) - { - case orientations.LANDSCAPE_LEFT: - { - Nav.GridContainer.classList.add("Landscape", "Left"); - } break; - case orientations.LANDSCAPE_RIGHT: - { - Nav.GridContainer.classList.add("Landscape", "Right"); - } break; - case orientations.PORTRAIT: - { - Nav.GridContainer.classList.add("Portrait"); - } break; - } + CineraProps.Orientation = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile); + UseOrientation(CineraProps.Orientation); } } +function +ComputePossibleCellsInDimension(AvailableSpaceInPixels, GridGap) +{ + var Result = 0; + var SpaceToFill = AvailableSpaceInPixels; + if(SpaceToFill >= Nav.MinButtonDim) + { + SpaceToFill -= Nav.MinButtonDim; + ++Result; + } + + for(; SpaceToFill >= (Nav.MinButtonDim + GridGap); ) + { + SpaceToFill -= (Nav.MinButtonDim + GridGap); + ++Result; + } + return Result; +} + +function +GridSizeMeetsMinimumSupported(GridSize) +{ + return GridSize.X * GridSize.Y >= 2; +} + +function +GridSizeIsSupported(GridSize) +{ + return (GridSize.X >= Nav.GridMinCellsPerDimension && GridSize.X <= Nav.GridMaxCellsPerDimension) && + (GridSize.Y >= Nav.GridMinCellsPerDimension && GridSize.Y <= Nav.GridMaxCellsPerDimension) && + GridSizeMeetsMinimumSupported(GridSize); +} + function ComputeOptimalGridSize() { - var Result = null; - var DimOffset = { + var Result = { + X: null, + Y: null, + }; + + var WindowDim; + if(CineraProps.IsMobile) + { + WindowDim = DeriveReliableWindowDimensions(); + } + else + { + WindowDim.X = document.body.clientWidth; + WindowDim.Y = document.body.clientHeight; + } + var DimReduction = { X: 0, Y: Nav.Controls.Header.offsetHeight, }; - if(CineraProps.Orientation == orientations.LANDSCAPE_LEFT || CineraProps.Orientation == orientations.LANDSCAPE_RIGHT) + Nav.Transition.ButtonsTransitionContainerElement.style = null; + Nav.ButtonsContainer.style = null; + Nav.Controls.GridTraversal.Header.style = null; + Nav.Controls.GridTraversal.Ascend.style = null; + Nav.Controls.GridTraversal.Prev.style = null; + Nav.Controls.GridTraversal.Next.style = null; + + // TODO(matt): Maybe structure it such that the grid is always not hidden at this point? + var GridWasHidden = Nav.GridContainer.classList.contains("hidden"); + if(GridWasHidden) { - DimOffset.X += Nav.Controls.GridTraversal.Header.offsetWidth; + Nav.GridContainer.classList.remove("hidden"); + } + if(CineraProps.IsMobile && (CineraProps.Orientation == orientations.LANDSCAPE_LEFT || CineraProps.Orientation == orientations.LANDSCAPE_RIGHT)) + { + DimReduction.X += Nav.Controls.GridTraversal.Header.offsetWidth; } else { - DimOffset.Y += Nav.Controls.GridTraversal.Header.offsetHeight; + DimReduction.Y += Nav.Controls.GridTraversal.Header.offsetHeight; + } + if(GridWasHidden) + { + Nav.GridContainer.classList.add("hidden"); } - var MaxWidth = MaxWidthOfElement(Nav.Nexus) - DimOffset.X; - var MaxHeight = MaxHeightOfElement(Nav.Nexus) - DimOffset.Y; + var MaxWidth = MaxWidthOfElement(Nav.Nexus, WindowDim) - DimReduction.X; + var MaxHeight = MaxHeightOfElement(Nav.Nexus, WindowDim) - DimReduction.Y; + + var BodyStyle = window.getComputedStyle(document.body); if(Nav.Nexus.parentNode == document.body) { // TODO(matt): Robustify this - var BodyStyle = window.getComputedStyle(document.body); MaxWidth -= parseInt(BodyStyle.marginRight); MaxHeight -= parseInt(BodyStyle.marginBottom); } - if(MaxWidth > MaxHeight) + Result.X = ComputePossibleCellsInDimension(MaxWidth, Nav.GridColumnGap); + Result.Y = ComputePossibleCellsInDimension(MaxHeight, Nav.GridRowGap); + + if(GridSizeMeetsMinimumSupported(Result)) { - MaxWidth = MaxHeight; - } - else if(MaxHeight > MaxWidth) - { - MaxHeight = MaxWidth; + Result.X = Clamp(Nav.GridMinCellsPerDimension, Result.X, Nav.GridMaxCellsPerDimension); + Result.Y = Clamp(Nav.GridMinCellsPerDimension, Result.Y, Nav.GridMaxCellsPerDimension); + + var ButtonDimBasedOnX = Math.floor((MaxWidth - Nav.GridColumnGap * (Result.X - 1)) / Result.X); + var ButtonDimBasedOnY = Math.floor((MaxHeight - Nav.GridRowGap * (Result.Y - 1)) / Result.Y); + + Nav.ButtonDim = Math.min(ButtonDimBasedOnX, ButtonDimBasedOnY); + Nav.ButtonDim -= Nav.ButtonDim % 2; // NOTE(matt): Even-length helps CSS keep the head & tail's correct size when rotated 180 degrees + + var GridTemplateColumnsStyle = "repeat(" + Result.X + ", minmax(" + Nav.ButtonDim + "px, " + Nav.ButtonDim + "px))"; + Nav.ButtonsContainer.style.gridTemplateColumns = GridTemplateColumnsStyle; + + var GridTemplateRowsStyle = "repeat(" + Result.Y + ", " + Nav.ButtonDim + "px)"; + Nav.ButtonsContainer.style.gridTemplateRows = GridTemplateRowsStyle; + + Nav.GridDim.X = Nav.ButtonDim * Result.X + Nav.GridColumnGap * (Result.X - 1); + Nav.GridDim.Y = Nav.ButtonDim * Result.Y + Nav.GridRowGap * (Result.Y - 1); + + SetDim(Nav.Transition.ButtonsTransitionContainerElement, Nav.GridDim.X + "px", Nav.GridDim.Y + "px"); + + Nav.Controls.GridTraversal.Header.style.maxWidth = Nav.GridDim.X + "px"; + Nav.Controls.GridTraversal.Header.style.maxHeight = Nav.GridDim.Y + "px"; + + var TraversalButtonCount = 3; + if(Nav.Controls.GridTraversal.Header.scrollWidth > Nav.Controls.GridTraversal.Header.clientWidth) + { + var TraversalButtonDim = Nav.Controls.GridTraversal.Header.clientWidth / TraversalButtonCount; + SetDim(Nav.Controls.GridTraversal.Ascend, TraversalButtonDim + "px", TraversalButtonDim + "px"); + SetDim(Nav.Controls.GridTraversal.Prev, TraversalButtonDim + "px", TraversalButtonDim + "px"); + SetDim(Nav.Controls.GridTraversal.Next, TraversalButtonDim + "px", TraversalButtonDim + "px"); + } + if(Nav.Controls.GridTraversal.Header.scrollHeight > Nav.Controls.GridTraversal.Header.clientHeight) + { + var TraversalButtonDim = Nav.Controls.GridTraversal.Header.clientHeight / TraversalButtonCount; + SetDim(Nav.Controls.GridTraversal.Ascend, TraversalButtonDim + "px", TraversalButtonDim + "px"); + SetDim(Nav.Controls.GridTraversal.Prev, TraversalButtonDim + "px", TraversalButtonDim + "px"); + SetDim(Nav.Controls.GridTraversal.Next, TraversalButtonDim + "px", TraversalButtonDim + "px"); + } + } - var MinButtonSize = 100; - - var MinGridSize = 2; - var MaxGridSize = 4; - - Result = Clamp(MinGridSize, Math.floor(MaxWidth / MinButtonSize), MaxGridSize); - Nav.ButtonDim = (MaxWidth - Nav.GridRowGap * (Result - 1)) / Result; - - // TODO(matt): If Safari's head-item sizing bug proves to be a problem, use this: - /* - var ButtonStyleRuleSelector = "#cineraIndex #cineraIndexGrid .cineraButton.subdivision"; - var ButtonStyleRule = GetOrSetRule(ButtonStyleRuleSelector); - - ButtonStyleRule.style.width = Nav.ButtonDim + "px"; - ButtonStyleRule.style.height = Nav.ButtonDim + "px"; - */ - - var GridTemplateColumnsStyle = "repeat(" + Result + ", 1fr)"; - Nav.ButtonsContainer.style.gridTemplateColumns = GridTemplateColumnsStyle; - - var GridTemplateRowsStyle = "repeat(" + Result + ", " + Nav.ButtonDim + "px)"; - Nav.ButtonsContainer.style.gridTemplateRows = GridTemplateRowsStyle; - - Nav.ButtonsContainer.style.width = MaxWidth + "px"; - Nav.ButtonsContainer.style.height = MaxHeight + "px"; - - Nav.Transition.ButtonsTransitionContainerElement.style.width = MaxWidth + "px"; - Nav.Transition.ButtonsTransitionContainerElement.style.height = MaxHeight + "px"; - - Nav.GridWidth = MaxWidth; + ResetButtonsContainerClone(); // NOTE(matt): This reapplies the sorting Z-rotation return Result; } @@ -3274,29 +3469,36 @@ ToggleView() } else { - Nav.Controls.View.textContent = "View: Grid"; - Nav.ViewType = view_type.GRID; - if(MaintainingState()) + if(GridSizeIsSupported(Nav.GridSize)) { - ClearStateBit(state_bit.VIEW_LIST); - SetStateBit(state_bit.VIEW_GRID); - } - - if(!IsQuery()) - { - var TargetLevel = ComputeTargetLevelForViewport(); - EmptyTraversalStack(); - if(TargetLevel.Projects || TargetLevel.Entries) + Nav.Controls.View.textContent = "View: Grid"; + Nav.ViewType = view_type.GRID; + if(MaintainingState()) { - var ProjectsStack = BuildProjectsStack(TargetLevel); - DeriveTraversalStack(ProjectsStack, TargetLevel); + ClearStateBit(state_bit.VIEW_LIST); + SetStateBit(state_bit.VIEW_GRID); } - UpdateButtons(); - Nav.List.classList.add("hidden"); - Nav.GridContainer.classList.remove("hidden"); + if(!IsQuery()) + { + var TargetLevel = ComputeTargetLevelForViewport(); + EmptyTraversalStack(); + if(TargetLevel.Projects || TargetLevel.Entries) + { + var ProjectsStack = BuildProjectsStack(TargetLevel); + DeriveTraversalStack(ProjectsStack, TargetLevel); + } + Nav.List.classList.add("hidden"); + Nav.GridContainer.classList.remove("hidden"); - ScrollToWithOffset(Nav.Controls.GridTraversal.Header, Nav.Controls.Header.offsetHeight); + UpdateButtons(); + + ScrollToWithOffset(Nav.Controls.GridTraversal.Header, Nav.Controls.Header.offsetHeight); + } + } + else + { + // TODO(matt): Inform user that grid view is unavailable } } ScrollCondition = Nav.ViewType == view_type.GRID; @@ -3431,36 +3633,37 @@ BindControls() function InitButtons() { - var ButtonPrototype = document.createElement("div"); - ButtonPrototype.classList.add("cineraButton", "subdivision"); - for(var i = 0; i < Math.pow(Nav.GridSize, 2); ++i) + if(GridSizeIsSupported(Nav.GridSize)) { - Nav.ButtonsContainer.appendChild(ButtonPrototype.cloneNode()); - } + var ButtonPrototype = document.createElement("div"); + ButtonPrototype.classList.add("cineraButton", "subdivision"); + for(var i = 0; i < Nav.GridSize.X * Nav.GridSize.Y; ++i) + { + Nav.ButtonsContainer.appendChild(ButtonPrototype.cloneNode()); + } - var Buttons = Nav.Nexus.querySelectorAll(".cineraButton.subdivision"); - for(let j = 0; j < Buttons.length; ++j) - { - let Button = { - Element: Buttons[j], - Projects: [], - Entries: [], - HeadIndex: null, - TailIndex: null, - }; - - Buttons[j].addEventListener("click", function() { - let InteractionData = { - Element: this, - Button: Button, + var Buttons = Nav.ButtonsContainer.querySelectorAll(".cineraButton.subdivision"); + for(let j = 0; j < Buttons.length; ++j) + { + let Button = { + Element: Buttons[j], + Projects: [], + Entries: [], + HeadIndex: null, + TailIndex: null, }; - EnqueueInteraction(interaction_type.PUSH_BUTTON, InteractionData); - }); - Nav.Buttons.push(Button); + Buttons[j].addEventListener("click", function() { + let InteractionData = { + Element: this, + Button: Button, + }; + EnqueueInteraction(interaction_type.PUSH_BUTTON, InteractionData); + }); + + Nav.Buttons.push(Button); + } } - - BindKeys(); } function @@ -3471,9 +3674,7 @@ ReinitButtons() Nav.Buttons[0].Element.remove(); Nav.Buttons.shift(); } - RebindKeys(); InitButtons(); - UpdateButtons(); } function @@ -3600,20 +3801,48 @@ PseudoPushButton(Button) } function -InitResizeEventListener() +ResizeFunction() { - window.addEventListener("resize", function() { - var NewGridSize = ComputeOptimalGridSize(); - if(Nav.GridSize !== NewGridSize) + CineraProps.Orientation = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile); + if(CineraProps.IsMobile) + { + UseOrientation(CineraProps.Orientation); + } + var NewGridSize = ComputeOptimalGridSize(); + if(Nav.GridSize !== NewGridSize) + { + UnbindGridKeys(); + Nav.GridSize = NewGridSize; + ReinitButtons(); + BindGridKeys(); + SetHelpKeyAvailability(Nav.GridSize) + if(GridSizeIsSupported(Nav.GridSize)) { - Nav.GridSize = NewGridSize; - ReinitButtons(); var TargetLevel = Nav.TraversalStack[Nav.TraversalStack.length - 1]; var ProjectsStack = EmptyTraversalStackIntoProjectsStack(); DeriveTraversalStack(ProjectsStack, TargetLevel); - SetHelpKeyAvailability(Nav.GridSize) } - UpdateButtons(); + else if(Nav.ViewType == view_type.GRID) + { + ToggleView(); + // TODO(matt): Inform user that we've switched to the list view + } + ScrollToWithOffset(Nav.Nexus, 0); + } + UpdateButtons(); +} +function +InitResizeEventListener() +{ + window.addEventListener("resize", function() { + if(CineraProps.IsMobile) + { + window.setTimeout(ResizeFunction, 512); + } + else + { + ResizeFunction(); + } }); } @@ -3624,35 +3853,11 @@ InitOrientationChangeListener() { if(CineraProps.IsMobile) { - CineraProps.Orientation = window.orientation; - Nav.GridContainer.classList.remove("Portrait", "Landscape", "Left", "Right"); - switch(CineraProps.Orientation) - { - case orientations.LANDSCAPE_LEFT: - { - Nav.GridContainer.classList.add("Landscape", "Left"); - } break; - case orientations.LANDSCAPE_RIGHT: - { - Nav.GridContainer.classList.add("Landscape", "Right"); - } break; - case orientations.PORTRAIT: - { - Nav.GridContainer.classList.add("Portrait"); - } break; - } - - var NewGridSize = ComputeOptimalGridSize(); - if(Nav.GridSize !== NewGridSize) - { - Nav.GridSize = NewGridSize; - ReinitButtons(); - var TargetLevel = Nav.TraversalStack[Nav.TraversalStack.length - 1]; - var ProjectsStack = EmptyTraversalStackIntoProjectsStack(); - DeriveTraversalStack(ProjectsStack, TargetLevel); - SetHelpKeyAvailability(Nav.GridSize) - } - UpdateButtons(); + window.setTimeout(ResizeFunction, 512); + } + else + { + ResizeFunction(); } }; }