0

I have a static HTML web site. I want to store the the nav (top) menu in an external file so when I change the menu, I want to see the change in all pages.
I REALLY REALLY NEED to be able to see the web pages also locally (regular Windows user without the need to install additional software: Apache, PHP, Wamp, specific browsers, etc).

There are two similar StackOverflow questions that partially solves this issue using PHP, SSIand ... frames. None of the solutions is good for me:

  • Frames out of discussion obviously (bad from SEO POV and also obsolete in HTML5).
  • PHP and SSI will only work after the site was uploaded on the server so it won't work locally.

The solution I see is putting ALL the menu in an external JS file. However, all the JS examples I fave found still have some 'parts' of the menu in the HTML file.

So, it is possible to have all menu in a JS file and only a call (and no actual menu items) to that file in my HTML files? I only have basic knowledge of JS. But enough to adapt a generic example for my needs.

6
  • How about loading the navbar from ajax? Commented Sep 12, 2016 at 9:44
  • Can you not install Wamp and work locally? wampserver.com/en Commented Sep 12, 2016 at 9:48
  • @ThomasJames - That will be easy. But it is not about me. I could install Wamp. But other users that will use the web site locally, won't. It really must work 'offline' (browser side). Commented Sep 12, 2016 at 9:49
  • Without local server. AJAX won't work. You can't make http request without a server. Commented Sep 12, 2016 at 9:52
  • You could try this: css-tricks.com/snippets/jquery/… Commented Sep 12, 2016 at 9:58

5 Answers 5

6

menu.html

<ul>
    <li><a href="index.html">Home</a></li>
    <li><a href="active1.html">Contact</a></li>
    <li><a href="active2.html">About</a></li>
    <li><a href="active3.html">Portfolio</a></li>
</ul>

index.html

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>

<div id="nav"></div>

js file:

$(function() {

    $("#nav").load("menu.html");

    function activeNav() {
        var pgurl = window.location.href.substr(window.location.href.lastIndexOf("/")+1);
         $("#nav ul li a").each(function(){
              if($(this).attr("href") == pgurl || $(this).attr("href") == '' )
              $(this).addClass("active");
         });
    }

    setTimeout(function() {
        activeNav();
    }, 100);

});

The setTimeout lets the page load and then runs the function to see what link is active and then you can add a class in the css:

#nav ul li a.active {
        color: #ff0000;
        font-weight: bold;
    }
Sign up to request clarification or add additional context in comments.

4 Comments

No it doesn't have to, it can be separate or at the bottom of the page in <script>code</script> tags or in a separate file: <script src="script.js"></script>
You can download here and see how it's done: clients.urbanedgedesign.co.uk/SolarWind.zip
SEO question: I know that now Google Bot should be able to see and parse java scripts. Do you think it will see the links generated by this script?
Best to register an xml sitemap with Google after the site goes live so it knows what pages to index - xml-sitemaps.com
1

nav.html // you dont need to put html, body or etc. Just the nav itself.

<nav> bla bla </nav>

index.html

<!doctype html>
<html>

  <head>
    <title>onload test</title>
    <script>

    window.onload = function(){
    var xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function(){
        if(this.readyState == 4 && this.status == 200){
             document.getElementById('includeNav').innerHTML= '<object type="text/html" data="nav.html"></object>';
        }
    }

    xhttp.open('POST', 'nav.html', true); // method, location, async
    xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhttp.send(); }
    </script>
  </head>


  <body>
    <p>The load event fires when the document has finished loading!</p>
    <div id="includeNav"></div>
  </body>
</html>

TRY this. this might be the answer of your question.

2 Comments

xhttp itself. xhttp.open is creating a request which is post method (you can also use get). The xhttp.send is sending the request from the server. this.responseText is the returned data from the server.
I think this is a valid solution. But I accepted Thomas' answer as he provided a full working example and his solution does not involve Ajax (hacks). Many thanks.
1

You can have a look into HTML Imports.

Option 1: In the simplest case you can do it like that:

index.html (or any other page):

<!DOCTYPE html>
<html>
<head>
    <link rel="import" href="nav.html">
</head>
<body>
    My Page
    <script>
        var link = document.querySelector('link[rel="import"]');
        var nav = link.import.querySelector('nav');
        document.body.appendChild(nav.cloneNode(true));
    </script>
</body>
</html>

nav.html:

<nav>
    <ul>
        <li>link 1</li>
        <li>link 2</li>
        <li>link 3</li>
    </ul>
</nav>

More information at: http://www.html5rocks.com/en/tutorials/webcomponents/imports/

Option 2: Make full usage of the Web Components API and use stuff like your own HTML element, then the usage in all your files gets even easier (although the nav.html gets a little bit more complex).

index.html (or any other page):

<!DOCTYPE html>
<html>
<head>
    <link rel="import" href="nav.html">
</head>
<body>
    My Page
    <my-nav></my-nav>
</body>
</html>

nav.html

<nav>
    <ul>
        <li>link 1</li>
        <li>link 2</li>
        <li>link 3</li>
    </ul>
</nav>
<script>
    var navProto = Object.create(HTMLElement.prototype);
    var navDoc = document.currentScript.ownerDocument;
    navProto.createdCallback = function() {
        var shadow = this.createShadowRoot();
        var nav = navDoc.querySelector('nav');
        var clone = document.importNode(nav, true);
        shadow.appendChild(clone);
    };
    document.registerElement('my-nav', { prototype: navProto });
</script>

EDIT: A mentionable downside of both solution is the browser support:

So mainly it's Chrome (including Android) and Opera which support these features. Unfortunately it's not possible to use HTML imports without a web server because of security settings of the browser. You will get a console error like that:

Imported resource from origin 'file://' has been blocked 
from loading by Cross-Origin Resource Sharing policy: 
Invalid response. Origin 'null' is therefore not allowed access.

So you would need to start a simple web server like the nodejs module http-server or use a Chrome extension like Chrome Dev Editor which brings a built in web server https://chrome.google.com/webstore/detail/chrome-dev-editor/pnoffddplpippgcfjdhbmhkofpnaalpg?utm_source=chrome-app-launcher-info-dialog

10 Comments

Wow! Nice. I will try the code now! I will accept the answer (without actual testing, and until a better solution is provided). But this is probably the winner!
I updated my answer now including the full usage of the web components API.
The first example (as it is) is not working. Line 10: link.import is undefined
The second example is also not working. I use Firefox. Maybe the code is tide to a specific browser?
I'm sorry I should have mentioned that so far it's mainly supported by Chrome and Opera. I updated my answer. You're using Firefox I guess?
|
1

A copy of my answer on a different thread:

I think this is the easiest way of doing it without a server side language. Use a javascript library like W3Data. All you need to do is add the w3-include-html attribute to your div. Done!

If your menu is in a file called menu.html you'd do something like this.

<div w3-include-html="menu.html"></div> 

Comments

0

You can use JsRender/JsViews for this.

2 Comments

Thanks. I will look into this. The site seems interesting but definitively confusing. The main page doesn't even tell that this is about. But I see they have a 'get started' page. Maybe this will tell me if this JsRender, whatever it is, applies to me (fulfills my requirements). But it is promising ... :)
This might work but I will accept @MichaelTroger's answer since it only involves a few lines of code instead of a huge JS framework. Many thanks anyway,

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.