SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 52
  1. #1
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Navigation problems.

    Page: http://www.westeros.org/Citadel/Citadel-Frames.html
    CSS: http://www.westeros.org/Citadel/Citadel-Frames.css
    Javascript: http://www.westeros.org/Citadel/Mouseover-Frames.js & http://www.westeros.org/Citadel/Menu.js

    On the above page, I have the main menu on the left side. Clicking on any item in the main menu unhides the appropriate submenu on the right side. So far, so good (except in Opera). However, there's currently no way for visitors to tell which item out of the main menu they clicked on. And worse, once they click on an item from one of the submenus, they're taken to a new page which starts over with just the main menu displayed.

    To improve the navigation, I'd like to do the following:

    1) Once a user has clicked on an item from the main menu, I would like it to stay 'selected' (that is, showing the onmouseover version of the graphic) until another item on the main menu is clicked. I would also like to alter the pointer for that item to a standard arrow rather than the hand indicating a link.

    2a) Once a user has clicked on an item from the currently active sub menu, which will load the index page of the chosen section, I would like that currently active sub menu to start off unhidden as the new page loads.

    2b) As with the selected item from the main menu, I would like the selected item from the currently active sub menu to stay 'selected' (that is, showing the onmouseover version of the graphic) until another item on the main menu or the currently active sub menu is clicked. I would also like to alter the pointer for that item to a standard arrow rather than the hand indicating a link.

    I have no idea if any of this is possible, however. 2a I could perhaps see solving with some sort of window.onload function that checks which section of the site a page belongs to (each submenu item corresponds to a folder), to determine if it should start out with a submenu loaded or not? I am not sure how I would go about checking that, however.

  2. #2
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    1) There are a couple ways to do this. The simplest way involves creating an onclick handler that does the same thing as the onmouseover handler but also disables its own onmouseover/out handlers.

    Code:
    //somewhere near the top:
    var currentMenuItemId;
    HTML Code:
    <span onclick="menuClick('main01','QA');" onmouseover="menuMouseover('main01','main01b');" onmouseout="menuMouseout('main01','main01a');"><img class="MenuItem" name="main01" id="main01" ...
    Code:
    function menuClick(thisId, menuId) {
    	//make sure previous current menu is set to its old image
    	var currentMenuItem = document.getElementById(currentMenuItemId);
    	if (currentMenuItem)
    		currentMenuItem.parentNode.onmouseout();
    	currentMenuItemId = thisId;
    	ToggleSub(menuId);
    }
    
    function menuMouseover(id, imgsrc) {
    	if (currentMenuItemId != id)
    		changeImages(id, imgsrc);
    }
    
    function menuMouseout(id, imgsrc) {
    	if (currentMenuItemId != id)
    		changeImages(id, imgsrc);
    }
    Or something like that. Haven't tested it out.

    2a) You can pass some parameter in the URL query string (url?submenu=QA). As the new page loads, you can use document.write and location.search for each submenu div:

    Code:
    //somewhere near top:
    var qsSubmenu = location.search.match(/submenu=([^&]*)/);
    if (qsSubmenu) qsSubmenu = qsSubmenu[0];
    Replace <div id="MenuQA"> with:

    HTML Code:
    <script>
    document.writeln('<div id="MenuQA"' + (qsSubmenu == 'QA' ? 'style="display: block;" : '') + '>');
    </script>
    Do the same for the other submenus. Again, didn't test it out.

    2b) With the above code:

    Replace

    HTML Code:
    <img class="MenuItem" name="main01" src="Graphics/menu_main01a.gif" width="99" height="40" border="0" alt="Q &amp; A" title="Q &amp; A" />
    with:

    HTML Code:
    <script>
    document.writeln('<img class="MenuItem" name="main01" src="' + (qsSubmenu == 'QA' ? 'Graphics/menu_main01b.gif' : 'Graphics/menu_main01a.gif') + '" width="99" height="40" border="0" alt="Q &amp; A" title="Q &amp; A" />');
    </script>
    Last edited by Maian; Apr 25, 2005 at 05:41.

  3. #3
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So for 1), I replace both Menu.js and Mouseover-Frames.js with the code you suggest? And for each image I include:

    Code:
    var currentMenuItemId = 'main01';
    var currentMenuItemOrigImgsrc = 'main01a';
    Or do I keep the list of image pairs as it is in Mouseover-Frames.js currently? Seems something like that might be needed to preload the 'b' images.

    For 2a) and 2b), it unfortunately looks like I can't take the approach of using a parameter passed through the URL, as part of my site uses Expression Engine, which already does that for its own purposes. I am looking into a php solution for that part, however.

    Thanks for all the suggestions, though. I'll see where I can get with 1) at least.

  4. #4
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Made some mistakes. Re-read (1) again. currentMenuItemId should hold the id of the currently activated menu item.

  5. #5
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Okay, I've tried to implement this. I have combined Mouseover-Frames.js and Menu.js into a single file since they need to interact anyhow, but currently I am just getting the on/off toggling of the submenus, not the mouseovers.

    Regarding 'var currentMenuItemId;', should this go in the script, or on each page? I just realized that if it needs to go on each page, that too will probably fail on the sections that use Expression Engine.
    Last edited by Linda A; Apr 25, 2005 at 04:47.

  6. #6
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Regarding 'var currentMenuItemId;', should this go in the script, or on each page? I just realized that if it needs to go on each page, that too will probably fail on the sections that use Expression Engine.
    Yeah, that can go in the script. Actually, declaring that var isn't even necessary, since variables default to the global scope, but it's good programming practice (and it reminds yourself that "yes, this is a global var").

    Also, made another mistake. "if (currentMenuItemId == id)" should be "if (currentMenuItemId != id)". There might be other mistakes, but keep in mind that the idea is to "disable" onmouseout/over when it's not the currently selected menu.

  7. #7
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Okay, put that into the script too, and uploaded all the changes. Looks like I've done something wrong somewhere, though, since the mouseovers are still absent.

    Page: http://www.westeros.org/Citadel/Citadel-Frames.html
    Javascript: http://www.westeros.org/Citadel/Mouseover-Frames.js

  8. #8
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Made the change from "if (currentMenuItemId == id)" to "if (currentMenuItemId != id)", but still no mouseovers. I'm afraid I don't quite understand what does what, though.

    Also, I may be misunderstanding, but shouldn't it be the opposite of this:

    the idea is to "disable" onmouseout/over when it's not the currently selected menu.
    Shouldn't onmouseout/onmouseover be disabled for the currently selected menu item?

  9. #9
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, my bad

    You seem to be missing the changeImages function.

  10. #10
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah-ha. Thank you.

    I accidentally replaced that whole bit with your new code. No wonder that caused a problem.

    By the look of it, that part mostly works now, except one small issue: if I click an item on the main menu, and then click another, the first stays at the 'b' image stage until it is moused over again. But maybe it isn't easily doable to have the Click() function make sure that the other items go back to the 'a' image?

    I am starting to realize why I stuck with a not-so-good-but-simple navigation for a long while.

  11. #11
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You need id's as well:

    Code:
    <img class="MenuItem" id="main01" name="main01" src="Graphics/menu_main01a.gif" width="99" height="40" border="0" alt="Q &amp; A" title="Q &amp; A" />

  12. #12
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Should 'name' be kept in, or is just 'id' enough?

    At the moment, I have both in, but I still have the same issue: if I click an item on the main menu, and then click another, the first stays at the 'b' image stage until it is moused over again.

  13. #13
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    For backwards compatibility, keep both.

    This should fix it:

    Code:
    function menuClick(thisId, menuId) {
    	//make sure previous current menu is set to its old image
    	var currentMenuItem = document.getElementById(currentMenuItemId);
    	currentMenuItemId = thisId;
    	if (currentMenuItem)
    		currentMenuItem.parentNode.onmouseout();
    	ToggleSub(menuId);
    }
    Before calling onmouseout, make sure currentMenuItemId is not currentMenuItem's id, since onmouseout exits if they are equal.

  14. #14
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That fixed it, thank you!

  15. #15
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Since getting the mouseover/out/click part of the navigation to work, I have been trying to figure out how to deal with the remaining issue: how do I ensure that when someone moves from, for example, /Citadel/index.html to /Citadel/FAQ/index.html (or accesses the latter page directly through a link), how do I make sure that this page loads with:

    a) the right item on the Menu in the 'b' state (in this case, the 'Q & A' button)
    b) the right SubMenu loaded (in this case, the 'Q & A' SubMenu)
    c) the right item on the SubMenu in the 'b' state (in this case, the 'FAQ' button)

    I was most of the way to a PHP solution for b), when I realized that this would conflict with the javascript, so I am thinking I will need either a pure javascript or a pure PHP solution. But PHP can't be used for mouseover/out/click actions, can it?

    Edited to add: The page can now be found at http://www.westeros.org/Citadel/ instead of at the temporary location. This way, the navigation can be tested out more easily within all the folders.

  16. #16
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you can pass the current submenu id over the URL, you can use mostly PHP and a snippet of Javascript to get it to work. I'm not familiar with the Expression Engine, but are you sure you can't use the query string?

  17. #17
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Since Expression Engine itself uses query strings extensively to determine the content of the dynamic pages, I think it is very likely that it would cause a conflict.

    I have it mostly solved how to determine which folder the page is within through PHP, but I don't suppose I can use PHP to call or trigger, for example, the ToggleSub() function on interior pages? Or to pass a value that the javascript can use in some other fashion than through the URL?

  18. #18
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    As long as you can get current submenu id (which it sounds like you can get from the folder name), it'll work.

    PHP Code:
    <script>
    var currentMenuItemId = <?=$menu_item_id?>;

    oldWindowOnload = window.onload;
    window.onload = function() {
        if (oldWindowOnload)
            oldWindowOnload();
        ToggleSub(<?=$submenu_id?>);
    }
    </script>

  19. #19
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hrm, yes, I think I could have $SubMenu[$folders] be equal to 'QA', for example. But is it enough if this bit of php code is just included somewhere on the page?

    However, if I change the javascript to use <?=$submenu_id?>, doesn't that mean that the user will no longer be able to manually toggle between submenus? Since that would be necessary for them to actually navigate away from the section they've reached.

    Or would this ToggleSub function not interfer with the other one?

    If this works, can I use a similar approach to solve a) and c)?

    Edited to add:

    This is the PHP used:

    Code:
    <?php 
    
    $MenuItem = Array ( 
    '/Citadel/' => None,
    '/Citadel/FAQ' => QA,
    '/Citadel/SSM' => QA,
    '/Citadel/Concordance' => Theme,
    '/Citadel/Encyclopaedia' => Theme,
    '/Citadel/Heraldry' => Theme,
    '/Citadel/History' => Theme,
    '/Citadel/Characters' => Story,
    '/Citadel/Prophecies' => Story,
    '/Citadel/Artwork' => Miscellany,
    '/Citadel/Books' => Miscellany,
    '/Citadel/Images' => Miscellany,
    '/Citadel/Links' => Miscellany
    ); 
    
    $SubMenu = Array ( 
    '/Citadel/' => None,
    '/Citadel/FAQ' => QA,
    '/Citadel/SSM' => QA,
    '/Citadel/Concordance' => Theme,
    '/Citadel/Encyclopaedia' => Theme,
    '/Citadel/Heraldry' => Theme,
    '/Citadel/History' => Theme,
    '/Citadel/Characters' => Story,
    '/Citadel/Prophecies' => Story,
    '/Citadel/Artwork' => Miscellany,
    '/Citadel/Books' => Miscellany,
    '/Citadel/Images' => Miscellany,
    '/Citadel/Links' => Miscellany
    ); 
    
    $SubMenuItem = Array ( 
    '/Citadel/' => None,
    '/Citadel/FAQ' => FAQ,
    '/Citadel/SSM' => SSM,
    '/Citadel/Concordance' => Concordance,
    '/Citadel/Encyclopaedia' => Encyclopaedia,
    '/Citadel/Heraldry' => Heraldry,
    '/Citadel/History' => History,
    '/Citadel/Characters' => Characters,
    '/Citadel/Prophecies' => Prophecies,
    '/Citadel/Artwork' => Artwork,
    '/Citadel/Books' => Books,
    '/Citadel/Images' => Images,
    '/Citadel/Links' => Links
    ); 
    
    $URL = $_SERVER['PHP_SELF'];
    
    $Folders = substr($URL,0,strrpos($URL,"/"));
    
    $WhichMenuItem = $MenuItem[$Folders];
    
    $WhichSubMenu = $SubMenu[$Folders];
    
    $WhichSubMenuItem = $SubMenuItem[$Folders];
    
    ?>
    I've only been able to test it to a limited degree, but I think it works. Currently, its included on each page via a PHP include, although I don't know if you can use those between <head></head>, or? I put it there for now since that's where all the script, css, etc includes are, so it makes it easier to keep track of them.

    I also tried to add the bit of javascript you suggested (changed to use $WhichSubMenu) to my Mouseovers.js file, but that broke the regular functionality.
    Last edited by Linda A; Apr 28, 2005 at 04:39.

  20. #20
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I forgot the string quotes:

    PHP Code:
    var currentMenuItemId = '<?=$menu_item_id?>';

    oldWindowOnload = window.onload;
    window.onload = function() {
        if (oldWindowOnload)
            oldWindowOnload();
        ToggleSub('<?=$submenu_id?>');
    }
    </script>
    Also, I haven't programmed in php for years, so I don't know if what I wrote was valid php.

  21. #21
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'll try the PHP forum as well, to see if I can get it sorted out for certain on that end at least.

  22. #22
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It seems that it isn't possible to pass information between php and javascript in that fashion, so instead it was suggested that I use php to print out the needed javascript on each page.

    Currently, I have it putting this (with the ID varying depending on which folder the page is in) on each page:

    Code:
    <script language='javascript' >
    oldWindowOnload = window.onload;
    window.onload = function() {
    if (oldWindowOnload)
    oldWindowOnload();
    ToggleSub(QA);
    </script>
    This does nothing, however, even though the source shows that its there. Is it because the actual ToggleSub() function is in a seprate .js file?

  23. #23
    SitePoint Guru
    Join Date
    Feb 2005
    Posts
    602
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's not correct. QA needs to be 'QA' - it has to be a string. The code I wrote should work, barring an PHP syntax errors. PHP is processed server-side, while JS is processed client-side, so PHP will be processed first.

    Try using <?php echo $some_var; ?> instead of <?=$some_var?>.

  24. #24
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah, okay.

    With the quotes, the code works if I replace the variables with, for example, 'QA' and place that on the page. But no luck getting it to work with the PHP variables.

    I'll give having the PHP write out the javascript another try, though.

    A pure javascript solution is starting to look like a better option, but not sure how to get around the issue of retrieving the location of each page.

  25. #25
    SitePoint Evangelist
    Join Date
    Feb 2005
    Posts
    537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah-ha.

    Putting this into the PHP did it:

    Code:
    echo "<script language='javascript' >\n";
    echo "var currentMenuItemId = '$WhichSubMenu';\n"; 
    echo "oldWindowOnload = window.onload;\n";
    echo "window.onload = function() {\n";
    echo "if (oldWindowOnload)\n";
    echo "oldWindowOnload();\n";
    echo "ToggleSub('$WhichSubMenu');\n"; 
    echo "}\n";
    echo "</script>\n";
    Whew. Just too bad it can't insert it into another file to include instead of on each page, but that'll have to do for now.

    Do you think it would be doable to also set the right item on the Menu and the SubMenu to the 'b' state? I have a $MenuItem and a $SubMenuItem variable setup in PHP already; they'll resolve to, for example, main01 and qa02.

    I was thinking of just printing out part of the menuClick function in the same way in PHP, but I am not quite sure which parts to use to just change those two images and leave it at that until someone clicks another Menu or SubMenu item.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •