How to add javascript to level1 li($hc,1)

About the template and stylesheet - and changing the menu
Post Reply
svasti
Posts: 1659
Joined: Wed Dec 17, 2008 5:08 pm

How to add javascript to level1 li($hc,1)

Post by svasti » Tue Dec 30, 2014 9:03 pm

In order to ensure drop down menu to be always in viewport,
I'd like to add to all level 1 li($hc,1) something like

Code: Select all

<li class="docs" onMouseOver="nav(this);"><a href="/Svasti/?Start" >Start</a>
I guess it has to be done in function render() and I have to add kind of xli($hc,1). :?:

cmb
Posts: 14225
Joined: Tue Jun 21, 2011 11:04 am
Location: Bingen, RLP, DE
Contact:

Re: How to add javascript to level1 li($hc,1)

Post by cmb » Tue Dec 30, 2014 9:29 pm

svasti wrote:I guess it has to be done in function render() and I have to add kind of xli($hc,1).
You don't have to attach an event handler in the HTML, but instead you can attach it via JS (I usually prefer that anyway). The technique is like:
  • find the relevant elements
  • set their onmouseover attribute to a function
Finding the elements can be done with document.querySelectorAll() which expects a CSS selector, and is available on all modern browsers (down to IE 8). This function returns an array like structure which you can traverse with a for loop, e.g.:

Code: Select all

var lis = document.querySelectorAll(".mymenu > li");
for (var i = 0; i < lis.length; i++) {
    lis[i].onmouseover = function () {
        nav(this);
    };
}
This JS can be simply added to $bjs, either as inline script or by referring to an external script (<script src="...">). If you're using it in template.htm, the most simple solution is to put the script directly before the closing </body> tag (no need for $bjs in this case).
Christoph M. Becker – Plugins for CMSimple_XH

svasti
Posts: 1659
Joined: Wed Dec 17, 2008 5:08 pm

Re: How to add javascript to level1 li($hc,1)

Post by svasti » Tue Dec 30, 2014 9:51 pm

It works, when I put this code at the bottom of the html, but not when I put it in the head. I guess so kind of onload must precede?

cmb
Posts: 14225
Joined: Tue Jun 21, 2011 11:04 am
Location: Bingen, RLP, DE
Contact:

Re: How to add javascript to level1 li($hc,1)

Post by cmb » Tue Dec 30, 2014 10:06 pm

svasti wrote:It works, when I put this code at the bottom of the html, but not when I put it in the head. I guess so kind of onload must precede?
If you put it before the menu is emitted it will fail, because no `.menu > li` can be found (see also http://pointedears.de/scripts/faq/cljs/ ... oreDefined). You could put it in an event handler for the load event of window or the DOMContentLoaded event of document, but that raises the issue, that IE 8 doesn't support addEventListener(), and the fallback attachEvent() doesn't set `this` as expected (besides that DOMContentLoaded is not supported by IE 8, IIRC). Just put it at the bottom of the body -- it's well placed there.
Christoph M. Becker – Plugins for CMSimple_XH

svasti
Posts: 1659
Joined: Wed Dec 17, 2008 5:08 pm

Re: How to add javascript to level1 li($hc,1)

Post by svasti » Tue Dec 30, 2014 10:17 pm

Ah, that clarifies a lot. I did what you proposed and it's working great. Finally the drop down menu on the first item opens to the right and the one on the last item to the left, and with long menus in small screen it is adapting accordingly. Soon I'll update some of my templates with this feature.

cmb
Posts: 14225
Joined: Tue Jun 21, 2011 11:04 am
Location: Bingen, RLP, DE
Contact:

Re: How to add javascript to level1 li($hc,1)

Post by cmb » Tue Dec 30, 2014 10:43 pm

svasti wrote:Finally the drop down menu on the first item opens to the right and the one on the last item to the left
One could do this without any client side scripting, though. The :first-child and :last-child pseudo selectors come in handy here (if they are supported). You probably know this, but there might be readers who don't. :)
svasti wrote:and with long menus in small screen it is adapting accordingly
Indeed, that likely requires JS (CMIIW, please).
Christoph M. Becker – Plugins for CMSimple_XH

svasti
Posts: 1659
Joined: Wed Dec 17, 2008 5:08 pm

Re: How to add javascript to level1 li($hc,1)

Post by svasti » Tue Dec 30, 2014 11:32 pm

It is for small screens and long menus with line break in the menu line, where you don't know where the line is going to be.
The java script is measuring the distance to the screen border in order to decide which side the drop down should go, specially the 3rd level. Just to prevent that the 3rd level gets out of the viewport.

And as one never knows how long a menu gets and on what kind of device people a seeing the website, I was locking for some time for a solution. I went on trying all kinds of css solutions, the best I could come up until now was Blog1

Couldn't find anything fitting in the web. Even amongst our template designers drop down menus are rare.
So I finally came up with a little javascript myself and you gave the last necessary hint.

Code: Select all

<script type="text/javascript">
var lis = document.querySelectorAll(".menulevel1 > li");
for (var i = 0; i < lis.length; i++) {
    lis[i].onmouseover = function () {
        nav(this);
    };
}
function nav(el) {
    var data = el.getBoundingClientRect();
    var left = data.left;
    var right = document.documentElement.clientWidth - data.right;
    if (left > right) {
          document.getElementById("nav").className = "b";
     }
    if (left <= right) {
          document.getElementById("nav").className = "a";
     }
}
</script>

cmb
Posts: 14225
Joined: Tue Jun 21, 2011 11:04 am
Location: Bingen, RLP, DE
Contact:

Re: How to add javascript to level1 li($hc,1)

Post by cmb » Tue Jan 20, 2015 11:11 am

The script creates resp. changes three properties of the global object (window), namely lis, i and nav. You could easily avoid potential name clashes by enclosing the script in an IIFE:

Code: Select all

<script type="text/javascript">
(function () {
    var lis = document.querySelectorAll(".menulevel1 > li");
    // ...
}());
</script>
This would create a memory leak in old IE (< 8), but the script won't work in these browsers anyway.
Christoph M. Becker – Plugins for CMSimple_XH

svasti
Posts: 1659
Joined: Wed Dec 17, 2008 5:08 pm

Re: How to add javascript to level1 li($hc,1)

Post by svasti » Tue Jan 20, 2015 2:54 pm

Actually the script evolved quite a bit more before it found its way into some of my templates, and I finally also used an anonymous function. However with your suggestion it's still a bit nicer:

Code: Select all

<script type="text/javascript">
(function () {
    var lis = document.querySelectorAll(".menulevel1 > li");
    for (var i = 0; i < lis.length; i++) {
        lis[i].onmouseover = function () {
            var data = this.getBoundingClientRect();
            var left = data.left;
            var right = document.documentElement.clientWidth - data.right;
            var cl = "a";
            if (left > right) cl = "b";
            if(this.className.indexOf("sdocs") != -1) this.className = "sdocs " + cl;
            else this.className = cl;
        }
    }
}());
</script>
For instance in my roots template, without java script the drop down menu is centered, with java script the left 1st level li items get class a and the right ones class b. Class sdocs is preserved (will be underlined) to indicate the top page of the shown page.

With decreasing screen size the width of the drop down get narrower and the font size gets smaller, and sub 400px the 3rd level will be integrated in the drop down.

Post Reply