Snazzy Side Navigation Menu [solved and snazzy]

Hi folks,

I am trying to implement a side nav menu as per this w3schools link: https://www.w3schools.com/howto/howto_js_sidenav.asp

I am doing the first menu type "Sidenav overlay" (without any of the fancier options). There are 3 parts to this: the HTML text, the CSS layout, and the Javascript function that executes everything. All of the necessary code is there, but where and how to put this in my game leaves me headscratching.

I pasted the CSS and HTML into a string attribute called game.QuitBar (with the CSS first, as per the "Try it Yourself" example). Then, under my game's UI tab, I included JS.addText (game.QuitBar) and JS.addScript (game.QuitBar). I also made a JS script called QuitBar.js and added it to the left-side Javascript tree branch. Finally I made a "quit" command that calls JS.openNav (), which is one of the js functions inside QuitBar.js that should open the side nav menu.

When I start the game, JS.addText (game.QuitBar) prints out the code under divOutput but typing "quit" does nothing. JS.addScript (game.QuitBar) also apppears to do nothing when typing "quit". This should be straightforwardly doable, but how? HOW?!

This is all of the CSS and HTML inside game.QuitBar:

  .sidenav {
    height: 100%;
    width: 0;
    position: fixed;
    z-index: 1;
    top: 0;
    left: 0;
    background-color: #111;
    overflow-x: hidden;
    padding-top: 60px;
    transition: 0.5s;
  }
  .sidenav a {
    padding: 8px 8px 8px 32px;
    text-decoration: none;
    font-size: 25px;
    color: #818181;
    display: block;
    transition: 0.3s;
  }
  .sidenav a:hover {
    color: #f1f1f1;
  }
  .sidenav .closebtn {
    position: absolute;
    top: 0;
    right: 25px;
    font-size: 36px;
    margin-left: 50px;
  }
  <div id="mySidenav" class="sidenav">
    <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
    <a href="#">About</a>
    <a href="#">Services</a>
    <a href="#">Clients</a>
    <a href="#">Contact</a>
  </div>
  <span onclick="openNav()">open</span>

Here's the js script QuitBar.js that gets the mySidenav element under game.QuitBar:

function openNav() {
    document.getElementById("mySidenav").style.width = "250px";
};
function closeNav() {
    document.getElementById("mySidenav").style.width = "0";
};

OK ... you should use JS.addText() to add HTML only.
To include the CSS within the HTML, you need to put <style> before it and </style> after – this should move the sidebar to the right place, and make it's initial width 0.

You shouldn't be calling JS.addScript() unless you're adding javascript.

In this example, the CSS hides the navbar, and the JS changes the CSS. So while your CSS is missing its <style> tags, the navbar appears in the normal output area, and your quit command doesn't make it appear because it isn't hidden.

(Feel free to ignore this bit) The JS looks OK, but could be more elegant. As Quest is already using jQuery, it's more efficient to use jQuery throughout (as it smooths over the differences between browsers for you).
A jQuery version of that script would be:

function openNav() {
    $("#mySidenav").css({width: 250});
};
function closeNav() {
    $("#mySidenav").css({width: 0});
};

(If you want to be flashy, you can change css to animate in that script)


Thank you for the quick response and education! I will try this out now! If I can get it working, I will fool around with extra snazz like animate!


K.V.

I tried to do this about 2 months ago, got angry, turned green, smashed stuff, and eventually gave up.


I tried to do this for about 2 hours this morning, got angry, turned green, smashed stuff, and just gave up.


K.V.

Okay, I couldn't give up.

OLD CODE

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Sidebar (DrAgon)">
    <gameid>40e27116-5623-4ab0-8a2d-8c82cbf55c73</gameid>
    <version>1.1</version>
    <firstpublished>2018</firstpublished>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <description type="string"></description>
    <beforeenter type="script"><![CDATA[
      JS.addText ("<style> .sidenav  {  height: 100%;    width: 0;    position: fixed;  transition: 0.5s;  z-index: 1000;    top: 0;    left: 0;    background-color: #111;    overflow-x: hidden;    padding-top: 60px;   } .sidenav a {   padding: 8px 8px 8px 32px;    text-decoration: none;  transition: 0.5s;  font-size: 25px;    color: #818181;    display: block;   } .sidenav a:hover {   color: #f1f1f1;  } .sidenav .closebtn {   position: absolute;    top: 0;    right: 25px;    font-size: 36px;    margin-left: 50px; }#sidenav-open{top:25px;}</style>")
      msg ("<div id=\"mySidenav\" class=\"sidenav\"><br/>    <a href=\"javascript:void(0)\" class=\"closebtn\" onclick=\"closeNav()\">&times;</a><br/>    <a href=\"#\">About</a><br/>    <a href=\"#\">Services</a><br/>    <a href=\"#\">Clients</a><br/>    <a href=\"#\">Contact</a><br/>  </div><span id=\"sidenav-open\" style=\"font-size:30px;cursor:pointer;top:0;position:fixed;\" onclick=\"openNav()\">&#9776; Menu</span>")
      JS.eval("$('body').append($(#'mySidenav'));")
      JS.eval("$('body').append($('#sidenav-open'));")
      JS.eval("function openNav() {    $(\"#mySidenav\").css({width: 250});};function closeNav() {    $(\"#mySidenav\").css({width: 0});};")
    ]]></beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
  </object>
</asl>


K.V.

UPDATED


The Example Game's code:

<!--Saved by Quest 5.7.6606.27193-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Sidebar (DrAgon)">
    <gameid>40e27116-5623-4ab0-8a2d-8c82cbf55c73</gameid>
    <version>2.0</version>
    <firstpublished>2018</firstpublished>
    <feature_advancedscripts />
    <contactaddress>PUT_YOUR_EMAIL_ADDRESS_HERE</contactaddress>
    <inituserinterface type="script"><![CDATA[
      JS.eval ("function navCmdClick(cmd){addText('<br/>>'+cmd+'<br/>');ASLEvent('HandleSingleCommand', cmd);scrollToEnd();}")
      JS.addText ("<style> .sidenav  {  height: 100%;    width: 0;    position: fixed;  transition: 0.5s;  z-index: 1000;    top: 0;    left: 0;    background-color: #111;    overflow-x: hidden;    padding-top: 60px;   } .sidenav a {   padding: 8px 8px 8px 32px;    text-decoration: none;  transition: 0.5s;  font-size: 25px;    color: #818181;    display: block;   } .sidenav a:hover {   color: #f1f1f1;  } .sidenav .closebtn {   position: absolute;    top: 0;    right: 25px;    font-size: 36px;    margin-left: 50px; }#sidenav-open{top:25px;}</style>")
      msg ("<div id=\"mySidenav\" class=\"sidenav\"><br/>    <a href=\"#\" class=\"closebtn\" onclick=\"closeNav()\">&times;</a></div><span id=\"sidenav-open\" style=\"font-size:30px;cursor:pointer;top:0;position:fixed;\" onclick=\"openNav()\">&#9776; Menu</span>")
      JS.eval ("$('body').append($(#'mySidenav'));")
      JS.eval ("$('body').append($('#sidenav-open'));")
      JS.eval ("function openNav() {    $(\"#mySidenav\").css({width:'15vw'});};function closeNav() {    $(\"#mySidenav\").css({width: 0});};")
      AddSidenavCmdLink ("Help")
      AddSidenavCmdLink ("Look")
      AddSidenavCmdLink ("Wait")
      AddSidenavContactLink
    ]]></inituserinterface>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <description type="string"></description>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
  </object>
  <function name="AddSidenavCmdLink" parameters="cmd"><![CDATA[
    JS.eval ("$('#mySidenav').append('<a href=\"#\" class=\"sidenav-cmdlink\" onclick=\"navCmdClick($(this).html())\">"+cmd+"</a><br/>');")
  ]]></function>
  <function name="AddSidenavContactLink"><![CDATA[
    JS.eval ("$('#mySidenav').append('<a href=\"mailto:"+game.contactaddress+"?subject="+game.gamename+"\">Contact</a><br/>');")
  ]]></function>
</asl>

K.V.

This is basically all you need (remember to add your email address to game.contactaddress)

EDIT: Added notes

    <inituserinterface type="script"><![CDATA[
      // Setup navCmdClick() function to handle sideNav command link clicks
      JS.eval ("function navCmdClick(cmd){addText('<br/>>'+cmd+'<br/>');ASLEvent('HandleSingleCommand', cmd);scrollToEnd();}")
      // Add the CSS
      JS.addText ("<style> .sidenav  {  height: 100%;    width: 0;    position: fixed;  transition: 0.5s;  z-index: 1000;    top: 0;    left: 0;    background-color: #111;    overflow-x: hidden;    padding-top: 60px;   } .sidenav a {   padding: 8px 8px 8px 32px;    text-decoration: none;  transition: 0.5s;  font-size: 25px;    color: #818181;    display: block;   } .sidenav a:hover {   color: #f1f1f1;  } .sidenav .closebtn {   position: absolute;    top: 0;    right: 25px;    font-size: 36px;    margin-left: 50px; }#sidenav-open{top:25px;}</style>")
      // Add the sidenav element
      msg ("<div id=\"mySidenav\" class=\"sidenav\"><br/>    <a href=\"#\" class=\"closebtn\" onclick=\"closeNav()\">&times;</a></div><span id=\"sidenav-open\" style=\"font-size:30px;cursor:pointer;top:0;position:fixed;\" onclick=\"openNav()\">&#9776; Menu</span>")
      // Move it to the body element
      JS.eval ("$('body').append($('#mySidenav'));")
      // Move the button, too.
      JS.eval ("$('body').append($('#sidenav-open'));")
      // Set up the openNav() and closeNav() functions
      JS.eval ("function openNav() {    $(\"#mySidenav\").css({width:'15vw'});};function closeNav() {    $(\"#mySidenav\").css({width: 0});};")
      // Add links!
      AddSidenavCmdLink ("Help")
      AddSidenavCmdLink ("Look")
      AddSidenavCmdLink ("Wait")
      AddSidenavContactLink
    ]]></inituserinterface>
  <function name="AddSidenavCmdLink" parameters="cmd"><![CDATA[
    // Add a link with "cmd" as the text, which will handle the command on click
    JS.eval ("$('#mySidenav').append('<a href=\"#\" class=\"sidenav-cmdlink\" onclick=\"navCmdClick($(this).html())\">"+cmd+"</a><br/>');")
  ]]></function>
  <function name="AddSidenavContactLink"><![CDATA[
    // Add a link with a mailto href, which pulls the email address from game.contactaddress
    JS.eval ("$('#mySidenav').append('<a href=\"mailto:"+game.contactaddress+"?subject="+game.gamename+"\">Contact</a><br/>');")
  ]]></function>

Yeah, I got it to work mrangel's way by adding the style tags. And I replaced the dead, example weblinks with ASLEvent scripts to call a function to handle the various choices. KV's code is so over my head that I have to look backwards :P Thanks again guys!


That is so cool KV. And a name check, honoured.


K.V.

Ha! I was thinking Doctor Agon created this thread for some reason. (I've told you guys before: I'm crazy!)

Pretend it says "Sidenav (Dcoder)".

(We've already got a DrAgon Device floating around here somewhere, so he's covered already.)


K.V.

I got it to work mrangel's way by adding the style tags. And I replaced the dead, example weblinks with ASLEvent scripts to call a function to handle the various choices

That's what I did, too. mrangel's last code is what finally made it work for me.

I set the sidebar's width to '15vw', which seems to work out nicely with my display settings, and I made the z-index 1000.

Then, I just added functions to make it easy to add links. (I added notes to the last code I posted.)


If I printed the <style> stuff at the same time as the sidenav div, it didn't work online. So, I split them up.


I avoid adding JS stuff to string attributes because it ruins any chances of QuestJS correctly converting a game.


K.V.

BONUS CODE (not that Dcoder needs it, he already has a super-awesome map in his game):

Modified inituserinterface to display a map with a fullscreen menu background:

    <inituserinterface type="script"><![CDATA[
      // Setup navCmdClick() function to handle sideNav command link clicks
      JS.eval ("function navCmdClick(cmd){addText('<br/>>'+cmd+'<br/>');ASLEvent('HandleSingleCommand', cmd);scrollToEnd();}")
      // Add the CSS
      JS.addText ("<style> .sidenav  {  height: 100%;    width: 0;    position: fixed;  transition: 0.5s;  z-index: 1000;    top: 0;    left: 0;    background-color: #111;    overflow-x: hidden;    padding-top: 60px;   } .sidenav a {   padding: 8px 8px 8px 32px;    text-decoration: none;  transition: 0.5s;  font-size: 25px;    color: #818181;    display: block;   } .sidenav a:hover {   color: #f1f1f1;  } .sidenav .closebtn {   position: absolute;    top: 0;    right: 25px;    font-size: 36px;    margin-left: 50px; }#sidenav-open{top:25px;}</style>")
      // Add the sidenav element
      msg ("<div id=\"mySidenav\" class=\"sidenav\"><br/>    <a href=\"#\" class=\"closebtn\" onclick=\"closeNav()\">&times;</a> <center><img width=\"100%\" src=\""+GetFileURL("EasterEggsMap.png")+"\"/></center></div><span id=\"sidenav-open\" style=\"font-size:30px;cursor:pointer;top:0;position:fixed;\" onclick=\"openNav()\">&#9776; Map</span>")
      // Move it to the body element
      JS.eval ("$('body').append($('#mySidenav'));")
      // Move the button, too.
      JS.eval ("$('body').append($('#sidenav-open'));")
      // Set up the openNav() and closeNav() functions
      JS.eval ("function openNav() {    $(\"#mySidenav\").css({width:'100vw'});};function closeNav() {    $(\"#mySidenav\").css({width: 0});};")
    ]]></inituserinterface>

This is the bit where you add your own image file's name:

<img width=\"100%\" src=\""+GetFileURL("EasterEggsMap.png")+"\"/>


GIF


EXTRA BONUS CODE

Want to stick the Quest map in there?

VERSION 2

    <inituserinterface type="script"><![CDATA[
      // Setup navCmdClick() function to handle sideNav command link clicks
      JS.eval ("function navCmdClick(cmd){addText('<br/>>'+cmd+'<br/>');ASLEvent('HandleSingleCommand', cmd);scrollToEnd();}")
      // Add the CSS
      JS.addText ("<style> .sidenav  {  height: 100%;    width: 0;    position: fixed;  transition: 0.5s;  z-index: 999;    top: 0;    left: 0;    background-color: #111;    overflow-x: hidden;    padding-top: 60px;   } .sidenav a {   padding: 8px 8px 8px 32px;    text-decoration: none;  transition: 0.5s;  font-size: 25px;    color: #818181;    display: block;   } .sidenav a:hover {   color: #f1f1f1;  } .sidenav .closebtn {   position: absolute;    top: 0;    right: 25px;    font-size: 36px;    margin-left: 50px; }#sidenav-open{top:25px;}</style>")
      // Add the sidenav element
      msg ("<div id=\"mySidenav\" class=\"sidenav\"><br/>    <a href=\"#\" class=\"closebtn\" onclick=\"closeNav();\">&times;</a> <center><span id='map-holder' /></center></div><span id=\"sidenav-open\" style=\"font-size:30px;cursor:pointer;top:0;position:fixed;\" onclick=\"openNav()\">&#9776; Map</span>")
      // Move it to the body element
      JS.eval ("$('body').append($('#mySidenav'));")
      // Move the button, too.
      JS.eval ("$('body').append($('#sidenav-open'));")
      JS.eval ("$('#map-holder').append($('#gridCanvas'));uiHide('#gridPanel');$('#gamePanelSpacer').height(0);")
      // Set up the openNav() and closeNav() functions
      JS.eval ("function openNav() {    $(\"#mySidenav\").css({width:'100vw'});};function closeNav() {    $(\"#mySidenav\").css({width: 0});};")
    ]]></inituserinterface>


Well this is cool!


This should be a relatively simple (I think) question:

I have a "quit" command that opens the sidenav. I want the sidenav to close if the "quit" command is entered again while the sidenav is still open (a toggle switch). So within my "quit" command, I need to first check for the opened/closed state of the sidenav, then use an if/then script to determine what to do. So how do I check for the opened/closed state of the sidenav?

MrAngel's javascript:

function openNav() {
    $("#mySidenav").css({width: 250});
};
function closeNav() {
    $("#mySidenav").css({width: 0});
};

The most direct way would be to check for the value of the CSS width in #my Sidenav?
Or to create and return a js var to Quest which could then be checked?


Returning JS variables to Quest isn't too neat.

If the menu starts visible, you could do:
$("#mySidenav").animate({width: 'toggle'});

The special value 'toggle' counts as 0 the first time it's used, and returns the sidebar to its previous width the next time.

At the moment, your sidebar starts with width 0; that's a bit harder to work with because jQuery doesn't know what size to make it appear at. But if you change the CSS, replacing:

width: 0;

with

width: 250px;
display: none;

I think you could use the toggle line above to both show and hide it.
(you could also change the width in the toggle line to left, opacity, or a few other properties

(If you want to use toggle without animating, then the functions are:

  • $("#mySidenav").show();
  • $("#mySidenav").hide();
  • $("#mySidenav").toggle();

I didn't want to use animate. I couldn't figure out the code to toggle either the width or the display:

$("#mySidenav").css({width: 'toggle'}); doesn't work. $("#mySidenav").toggle(); also doesn't work.

How does js know which property that you want to toggle?


K.V.

You'll need to choose a width. Let's say 250px.

In this bit of the CSS : .sidenav { height: 100%; width: 0;

Make it: .sidenav { height: 100%; width: 250px; display: none;

Then try $('#mySidenav').toggle().


EDIT

Be sure to change these functions to this:

function openNav() {   $('#mySidenav').show();};
function closeNav() {    $('#mySidenav').hide();};

Ok, I did as KV said before his EDIT:

 .sidenav {
    height: 100%;
    width: 250;
    display: none;
    position: fixed;
    z-index: 1;
    top: 0;
    left: 0;
    background-color: #111;
    overflow-x: hidden;
    padding-top: 60px;
    transition: 0.5s;
  }

Then changed the JS script to (it's redundant):

function openNav() {
    $('#mySidenav').toggle('0.5s;')
};

function closeNav() {
    $("#mySidenav").toggle('0.5s;')
};

That works except for one tradeoff -- the sidenav loses the effect of this line: transition: 0.5s;, which gave the sidenav a "slideout" effect. Can I get that back? If not, I can live without it.


K.V.

Change all the code back.

Use this for the script in the command:

JS.eval ("if ($('#mySidenav').width() != '0') { closeNav(); addTextAndScroll('Menu closed.'); } else { openNav(); addTextAndScroll('Menu opened.');}")

Ok, I just found an answer: transition: display 0.5s; to get the "slideout" effect back! Sorry, KV, to get you to do your last bit of coding (which is above my paygrade anyway).


K.V.

My openNav() and closeNav() functions when NOT opening a full-screen menu:

JS.eval ("function openNav() {   $('#mySidenav').width(($(window).width() - $('#gameBorder').width()) / 2);};function closeNav() {    $('#mySidenav').width('0');};")

This will only take up the left side of the screen between the edge of the window and the edge of the game's output element.


K.V.

Ok, I just found an answer... Sorry, KV, to get you to do your last bit of coding...

That's okay. I do that to mrangel all the time!

(Plus, I learned a new trick, so I'm cool.)


Ok, so final code for my problem:

.sidenav {
  height: 100%;
  width: 275;
  position: fixed;
  z-index: 1;
  top: 0;
  left: 0;
  background-color: #111;
  overflow-x: hidden;
  padding-top: 60px;
  transition: display 0.5s;
  display: none;
}

And the JS:

function openNav() {
    $('#mySidenav').toggle('0.1s;');
};

function closeNav() {
    $("#mySidenav").hide('0.1s;');
};

For some reason, you have to define a speed after .toggle or .hide in order to make the "slideout" effect work. That, plus transition: display 0.5s; instead of just transition: 0.5s;.


That fill-up-the-left-side code is nice, KV. I might try to use that too.

After learning tons of things from you, KV, I think I finally taught you something that you didn't know -- that's a first for me...woohoo!


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums