@nicjedi
YES it’s “possible”!
Sorry to “revive this old topic”, but since I believe I “do have the Solution”, I think it might help some people with similar needs.
I’m going to explain it “step by step” (NB: depending on your “needs”, just “Step1” may actually “already be enough”), but just before, I’ll just mention the following:
-“DISCLAIMER”: although I’m certainly “a guy who does enjoy coding”, I must admit I’m a “COMPLETE N00B”, not only with respect to “Grav” (which I’ve just discovered a couple of days ago [enjoying it so far], and haven’t even completely read the “Content” section of the Tutorial yet), but also with “Twig” (which I had never heard of before), YAML (even Markdown); never learned PHP and of course, I’m NOT a “software developer” nor anything like that (but did “deduce the Solution” by “rummaging into Quark’s Twig files” and “figuring out how stuff work”), which should obviously imply that:
→ It is very likely that my “Twig code” will be quite “Barbaric”…
→ Also, notice that I’ll be “directly modifying the Quark Template”, which I guess is “not recommended (at all)” (I’ve read that the “good practice” is “use inheritance blablabla” but not read the documentation about that yet)
…Anyways, I hope it will still be helpful (and -who knows- maybe someone “more Experienced” than me can “adapt” my solution to something “cleaner”); here it is:
[NB: here, onpage_menu
should be set to false
!!]
STEP 1:
go to:
user/themes/quark/templates/macros/macros.html.twig
At the beginning, just after:
{% import _self as macros %}
(and before the for loop)
add the following code (which I actually took [and slightly modified] from modular.html.twig)
{% for module in page.collection() if module.header.visible is not same as(false) %}
{% set current_module = (module.active or module.activeChild) ? 'active' : '' %}
<li><a class="{{ current_module }}" href="{{ page.url }}#{{ module.menu|hyphenize }}">{{ module.menu }}</a></li>
{% endfor %}
The idea with this code is to display in the (sub)menu the -visible- modules of the modular page, with links to the correct “anchors”; however, as it is now, they probably still won’t appear (unless your modular pages “also” happen to have “regular” child pages).
So to be sure that the modules will appear, you should change the following line (still in macros.html.twig):
{% if p.children.visible.count > 0 %}
into something like:
{% if p.children.visible.count + p.collection.count > 0 %}
So that the “arrow and submenu” does appear even if the modular page doesn’t have “regular child pages” (since modules don’t count as “child pages”)
(I guess there is probably a “cleaner way” to do this)
==> At this point (you can test it!) it should already be “working” in the sense that:
-The (“visible”) modules do appear in the submenu (below the modular page) and clicking on them will send you to the modular page, at the desired “anchor”
(Note again that here, onpage_menu
should be set to false
!)
However, note that “for the moment”:
- Because of the (weird?) way “collection” works, it is possible (e.g. if you have pages with “grandchildren” etc) that -in some particular circumstances- some pages will now “appear twice” in some submenus (counted both as being in “children” and in “collection”)
- When you click on the links (to the “modules”), you get “teleported” to the correct place, but it doesn’t “beautifully scroll/move” to that place
SO:
-if you’re not experiencing the little “bug” described in (1) and are happy the way it works, you can -if you wish- “stop here”, otherwise, follow “Step 2”
-if you’re OK with “teleporting” to the correct anchor, you also don’t need to follow “Step 3”, otherwise, if you do want your page to “beautifully scroll to the desired place” when your’re in the module, have a look at “Step 3”
STEP 2:
In order to avoid having pages “counted twice” (as in “collection” AND “children”) I’d just advise to “encapsulate” the following code (the one we just added):
{% for module in page.collection() if module.header.visible is not same as(false) %}
{% set current_module = (module.active or module.activeChild) ? 'active' : '' %}
<li><a class="{{ current_module }}" href="{{ page.url }}#{{ module.menu|hyphenize }}">{{ module.menu }}</a></li>
{% endfor %}
into some “condition” that checks if the page is modular or not…
I thought there should be an attribute like “page.modular()” to check this, but apparently, as I tested it, it didn’t seem to work so I just manually added a “display_modules” (call it whatever you want) attribute in [each] modular page’s header;
so in my case, it gives:
{% if page.header.display_modules == true %}
{% for module in page.collection() if module.header.visible is not same as(false) %}
{% set current_module = (module.active or module.activeChild) ? 'active' : '' %}
<li><a class="{{ current_module }}" href="{{ page.url }}#{{ module.menu|hyphenize }}">{{ module.menu }}</a></li>
{% endfor %}
{% endif %}
BEWARE!
If you add such a condition, don’t forget to add, in the header of each modular page you wish to display the modules (on the menu) the line
display_modules: true
(here, the name “display_modules” is obviously arbitrary, as long as consistent with the condition in macros.html.twig)
STEP 3:
With step 1 and 2, everything should already be “working fine” (you’d have the equivalant of the above-suggested “redirecton trick” (by @julesw), but much faster and without needing to “artificially add regular child pages with redirections”)
But if you want your page to “beautifully scroll” rather than “teleporting”, you should then make use of the “js/singlepagenav.min.js” JavaScript (NB: we won’t modify that JavaScript [only call it] so no need to “open” it; however, we’ll modify the twig files that “call it”)
first go to:
user/themes/quark/templates/modular.html.twig
For the moment, the “singlepagenav” script is only called when onpage_menu
is true
, but we want it to also be called when it is set to false
, so we’ll just comment [or delete, but I guess “commenting” {# #}
is probably less risky] the following lines:
{% if show_onpage_menu %}
{% endif %}
{% if show_onpage_menu %}
{% endif %}
in the two fist blocks (NOT the third!), so you should end up with:
{% block javascripts %}
{# {% if show_onpage_menu %} #}
{% do assets.add('theme://js/singlepagenav.min.js') %}
{# {% endif %} #}
{{ parent() }}
{% endblock %}
and
{% block bottom %}
{{ parent() }}
{# {% if show_onpage_menu %} #}
<script>
// singlePageNav initialization & configuration
$('ul.navigation').singlePageNav({
offset: $('#header').outerHeight(),
filter: ':not(.external)',
updateHash: true,
currentClass: 'active'
});
</script>
{# {% endif %} #}
{% endblock %}
respectively, so that the “singlepagenav” script be called… however, as it is now, it will do nothing, since it will only concern “ul” HTML tags with class “navigation”…
At first glance, it may seem we could try to “simply” set the class of our submenus to “navigation”; I haven’t tried it, but I’m pretty sure it would generate a bug, at least in the case you have “several” such “modular pages with modules displayed in the menu”, as clicking into another [“external”] link (to “a different modular page”) would try to activate the “singlepagenav” script, and eventually fail.
→ so the idea is to make it “distinguish” the pages “from the same module” form “external” pages; and the most “obvious/straightforward” way for doing this (which immediately came to my mind, at least), was to associate the submenu’s elements [representing modules or child pages] to the page they belong to, and the call to the script to the “current page” [this could, for instance be done by using “page.menu” but I guess it’s “better/cleaner” to use “page.slug” instead, since it will avoid “spaces” etc], SO:
still in modular.html.twig in the bottom block (inside the <script>
), change:
$('ul.navigation').singlePageNav
into something like:
$('ul.sub_{{ page.slug }}').singlePageNav
(NB: here, the prefix “sub_” is completely arbitrary and optional, I just added it to try to make things a bit “more consistent” and possibly avoid clashes with “already existing class names”, although I guess this is quite unlikely to happen)
Now go to back to
user/themes/quark/templates/macros/macros.html.twig
and, just between {% if p.children.visible.count + p.collection.count > 0 %}
and {{ macros.nav_loop(p) }}
, change:
<ul>
into:
<ul class="sub_{{ p.slug }}">
(here again, the prefix “sub_” is arbitrary but should just be consistent with what you did just before)
Here it is!
Now everything should be “working”:
[With onpage_menu
set to “false” and possibly an extra display_modules: true
in the concerned modular pages’headers]
-The [“visible”] submodules should appear in a [drop-down] submenu below the module’s name, when you put the mouse on it
-Clicking on it while in another page sends you directly at the correct place [“anchor”]
-Clicking on a module’s name [on the submenu] while in being in the modular page makes the page “beautifully scroll” to the desired place
(Also no bug of “pages appearing twice in the menu”, nor “broken links in the menu”)
NB: Sorry if I didn’t express myself clearly (not being a native english speaker nor a programmer, I might [“sometimes”?] be using the “wrong words”), but I hope it could still be helpful!