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.

Community
  • 1
  • 1
Gabriel
  • 20,797
  • 27
  • 159
  • 293

5 Answers5

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;
    }
Thomas James
  • 687
  • 2
  • 6
  • 21
  • No it doesn't have to, it can be separate or at the bottom of the page in tags or in a separate file: – Thomas James Sep 12 '16 at 13:20
  • You can download here and see how it's done: http://clients.urbanedgedesign.co.uk/SolarWind.zip – Thomas James Sep 12 '16 at 13:33
  • 1
    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? – Gabriel Sep 12 '16 at 17:06
  • Best to register an xml sitemap with Google after the site goes live so it knows what pages to index - https://www.xml-sitemaps.com – Thomas James Sep 13 '16 at 11:10
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.

Gabriel
  • 20,797
  • 27
  • 159
  • 293
hdotluna
  • 5,514
  • 4
  • 20
  • 31
  • 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. – hdotluna Sep 12 '16 at 10:01
  • 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. – Gabriel Sep 12 '16 at 16:59
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

Gabriel
  • 20,797
  • 27
  • 159
  • 293
Michael Troger
  • 3,336
  • 2
  • 25
  • 41
  • 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! – Gabriel Sep 12 '16 at 10:21
  • I updated my answer now including the full usage of the web components API. – Michael Troger Sep 12 '16 at 10:28
  • The first example (as it is) is not working. Line 10: link.import is undefined – Gabriel Sep 12 '16 at 11:17
  • The second example is also not working. I use Firefox. Maybe the code is tide to a specific browser? – Gabriel Sep 12 '16 at 11:21
  • 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? – Michael Troger Sep 12 '16 at 11:21
  • Then won't work for me. As the OP states, I need it to work on 'regular' computers, without installing additional software such as PHP, Wamp, etc. Too bad because the code/solution was SO elegant. – Gabriel Sep 12 '16 at 11:23
  • PS: I just tried both solutions in Chrome and won't work too. – Gabriel Sep 12 '16 at 11:26
  • I see. And you can't use a portable version of Chrome or something for development? It doesn't require admin rights. When you need to publish it later on you could use PHP or something to include your file for broad support. I would assume that your server supports that, right? Or do you plan to publish at all? – Michael Troger Sep 12 '16 at 11:29
  • The files will be uploaded on server via FPT. But this is slow. So, we need to see the 'web site' before uploading it online. This is why it has to work without server-side technology. ANY user should be able to see the web pages in his default browser. No the 'any user' is just a Windows user. But later it might also be a Mac user. – Gabriel Sep 12 '16 at 11:34
  • I think the only solution (as I proposed in my original question) is to move ALL menu code (code and menu items) in a JS file. – Gabriel Sep 12 '16 at 11:40
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> 
Ahmed Mansour
  • 527
  • 5
  • 13
0

You can use JsRender/JsViews for this.

  • 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 ... :) – Gabriel Sep 12 '16 at 09:56
  • 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, – Gabriel Sep 12 '16 at 10:25