-
Notifications
You must be signed in to change notification settings - Fork 99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make a hierarchical menu in navstories #183
Conversation
The hierachical menu is based on the structure of the stories (permalink).
``` | ||
|
||
To exclude a single story from the navstories meny add the following | ||
metadata `.. hidefromnav: yep` (yep can be anything) to the story. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
or True
Proof-of-concept of a ConfigPlugin. By request on the mailing list. | ||
Started as a Proof-of-concept of a ConfigPlugin. By request on the mailing list. | ||
|
||
Changed to map the stories to a hierachical structure in the menu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, how deep down does this go? Do you realise you can have only one level of submenus?
|
||
Format of `NAVIGATION_LINKS_POST_NAVSTORIES` is identical to `NAVIGATION_LINKS`. | ||
|
||
Sorting and display names in menu can be controlled for top-level entries via `NAVSTORIES_CFG`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no example for this
Hi, See my comments inline 2016-10-31 18:17 GMT+01:00 Chris Warrick notifications@github.com:
|
Previous mail was sent twice by an failure, except a small fix, so the last
one had this fix:
This plugin generates menus and one level of submenus (further sub-levels
are mapped to first level submenus).
Br,
Benny
|
Please respond on GitHub, not via e-mail. As for the |
I have updated README.md |
Skips initial stories or pages from menu.
permalink of the story shall match one of the entries in NAVSTORIES_PATHS for the given language to be included in the menu.
I have installed v. 7.8.1 and found that default location for stories have been changed to pages, commit df8d5d2 made navstories work well for both pages and stories. Commit 5667017 lets navstories only add menu entries if initial path of permalink match an entry in NAVSTORIES_PATH. I think that was all for now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does the resulting menu look for a sample site?
@@ -38,12 +38,50 @@ def set_site(self, site): | |||
site.scan_posts() | |||
# NAVIGATION_LINKS is a TranslatableSetting, values is an actual dict | |||
for lang in site.config['NAVIGATION_LINKS'].values: | |||
# Which paths are navstories active for for lang? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one “for”
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'l fix it
|
||
permalink = p.permalink(lang) | ||
for s in navstories_paths: | ||
if permalink.startswith('/' + s + '/'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
startswith
can take a tuple.
navstories_paths = tuple('/' + s + '/' for s in navstories_paths) # above
...
if permalink.startswith(navstories_paths):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but next I have to remove '/' + s + '/'
, I don't know how to do it without regular expressions, and navstories_paths are not regular expressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the check using a tuple, then use a for loop to figure out the longest string that the permalink starts with.
Or perhaps:
navstories_paths = tuple(('/' + s.strip('/') + '/') for s in navstories_paths)
for p in site.pages:
permalink = p.permalink()
s_candidates = [s for s in navstories_paths if permalink.startswith(s)]
if not s_candidates:
continue
# get longest path
s = max(s_candidates, key=len)
navpath = permalink[len(s):].split('/')
Use case:
NAVSTORIES_PATHS = {DEFAULT_LANG: ('pages', 'pages/foo', 'pages/foo/bar')}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will change to your code.
Should p.permalink() not be p.permalink(lang)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
permalink = p.permalink(lang) | ||
for s in navstories_paths: | ||
if permalink.startswith('/' + s + '/'): | ||
navpath = permalink[2 + len(s):].split('/') # Permalink format '/A/B/' for a story in s/A/B.rst |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean here with the comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was just a note when I started chaing the plugin, I will remove it.
if 'NAVSTORIES_MAPPING' in site.config and lang in site.config['NAVSTORIES_MAPPING']: | ||
navstories_mapping = site.config['NAVSTORIES_MAPPING'][lang] | ||
for sk, sv in navstories_mapping: | ||
for i in range(len(new_all)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code looks like a mess. Could you make it more readable/understandable?
(Also, I’d drop that setting, it makes people too lazy)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First two lines:
I am checking if site.config['NAVSTORIES_MAPPING'][lang]
is defined before using it, is there a better way to do it?
I can rename sk and sv to be more readable (sk -> map_key, sv -> map_text), would that help?
I don't like to remove NAVSTORES_MAPPING
since this can control in which order the menu entries are included. I want the mapping from key to text because I like the folders to be without spaces and special chars (danish non-ascii chars, even when I am using UTF-8) but would like to have this in the menu text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- You could use TranslatableSetting on all your setting to make things less of a mess.
- Do the rename. And add some comments to explain your
range(len())
thing. - Aren’t you using
post.title()
? My point is, if you need that much customization for things (so page titles need to be different in nav and page), perhaps you’re better off making menus by hand, will be much simpler than messing with this plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1: Is there a example on using TranslatableSetting, I have searched the plugins repository for it, but didn't find much help.
2: I will do that
3: I am using post.title(), but would like to get a deeper menu
Demo site.
Nav and A menu entries are autogenerated. A is not listed in NAVSTORIES_MAPPING, so it comes after Nav.
https://slbs.dk/n/
The conf.py and directory struture under src/ is here: https://slbs.dk/n/listings/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Look at nikola.py in core for some samples, and at the utils.TranslatableSetting class (which is well-documented).
I have not a public demo site at the moment, I will create one. |
- Using smarter loops - Minor changes TODO: - p.permalink(lang) ->p.permalink() - Usage of TranslatableSetting
p.permalink(lang) Usage of TranslatableSetting |
Please use the
You can use those to avoid some checks when it comes to languages in settings. navstories_paths = utils.TranslatableSetting('navstories_paths', site.config['NAVSTORIES_PATHS'], site.config['TRANSLATIONS']) You can use |
Edit: Just fixed permalink(lang) - now the links don't link to default language :-). I think the first loop over the configuration variables is the smartest way to accept:
The loop in the top of the lang loop could be skipped, but I think it is easier to read. |
Create menu structure navpath based on permalink without language prefix, and links in menu including language.
But read config variables in a try...except in case a varible is missing.
I had not seen your previous comment - I have just incorporated it, but reading config variables are in a try-excpet to prevent errors if a variable is missed in conf.py. Example site https://slbs.dk/n/ have been updated. |
for i in self.conf_vars: | ||
# Read config variables in a try...except in case a varible is missing | ||
try: | ||
nav_config[i] = utils.TranslatableSetting(i.lower(), site.config[i], site.config['TRANSLATIONS']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i.lower()
is unnecessary, i
will do it too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know if it should be so - I will remove .lower()
How does your plugin behave when |
I am not sure if I understand your question about I will add text similar to this to the README.md: I don't know if that answers your question? |
But how does it react to |
That will not be handled good, it will give two entries in the main menu, one with submenu for all entries in
|
The .lower() isn't needed.
It also handles if a top level page and a submenu, e.g. /nav.rst (top) and /nav/*.rst (sub) It is easier to change how the menu should be generated.
Last commit 88ac1a8 changes handling of entries as e.g.
The indention '* ' can be controlled via conf.py. https://slbs.dk/n have been updated to show this. |
I don't think I have more changes to the plugin. |
navsties skips the lang path specified in TRANSLATIONS for the internal processing (not for the links), but there was an error there. permalink_nolang starts with /pages/... no matter the value of TRANSLATIONS. Version incr t. 1.0.1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I finally had a while (sorry for taking so long…). It generally looks good, but confusing in some places.
pass | ||
else: | ||
sub = [] | ||
# Find min/max depth in actual submenu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The min
and max
functions take iterables and key functions, so you can do this:
min_depth = min(topent[1], key=lambda p: len(p[0]))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done :-)
prefix = self.navstories_submenu_indention * (len(p[0]) - min_depth) | ||
sub.append(tuple([p[1], prefix + p[2]])) | ||
ret.append(tuple([tuple(sub), title])) | ||
return tuple(ret) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought you were returning a list in this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it returns a tuple of the same format as NAVIGATION_LINKS (appended to NAVIGATION_LINKS as the last thing that navstories do)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PS. you misspell tuple
a lot in your code, so s/tuble/tuple/
please.
- Page title | ||
Example: | ||
[ [ 'Menu text for nav', | ||
[ [['nav'], '/pages/nav/', 'nav/'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you could make those instances of a NavNode class for better readability (and less random [i][n][d][e][x][i][n][g] everywhere)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NavNode is a class that you suggests that I create?
I think NavNode should contain:
Member variables:
- hierachy
- permalink
- title
And maybe a constructor method for creating the content based on the page variable (p)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should do it.
# navstories config for lang | ||
nav_conf_lang = {} | ||
for i in self.conf_vars: | ||
nav_conf_lang[i] = nav_config[i].values[lang] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nav_config[i](lang)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have seen .values[lang]
have been used elsewhere, is the result the same of nav_config[i].values[lang]
and nav_config[i](lang)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.values
is internal use and will break if someone assumes the usual behaviour of using default value if language is untranslated to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should site.config['NAVIGATION_LINKS'].values[lang]
also be changed?
And what about for lang in site.config['NAVIGATION_LINKS'].values:
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for
→ can’t be changed, not iterable
other instances where there is no iteration: go ahead
|
||
# Map to tuble | ||
new_entries = self.map_to_menu(new) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn’t an OrderedDict work better for new
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will let it be an array of navNode's since title=None for entries not in NAVSTORIES_MAPPING
, and it would be title there was the natural choise for key in the dict.
title = topent[0] | ||
if not title: | ||
# Default is 1th level of navpath | ||
title = topent[1][0][0][0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why one, zero, zero, zero? Those indexes are really hard to follow.
That said, you could get rid of at least one by doing
for title, topent_one in entries:
(come up with better name for topent_one
), or perhaps OrderedDict (as noted below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will take a look on that.
Chris Warrick (Kwpolska) says: .values is internal use and will break if someone assumes the usual behaviour of using default value if language is untranslated to.
NavNode is a new class with parameters for a page (navpath, permalink and title.
I have implemented the changes, should I increment the version number again, or is it only when on master it should be incremented? |
Those version numbers don’t matter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good, merging.
navpath = permalink_nolang[len(s):].strip('/').split('/') | ||
if len(navpath) == 0: | ||
# Should not happen that navpath is empty, but to prevent errors, and inform via a warning | ||
LOGGER.warn("Page with permalink: '%s', title: '%s', not added to menu by navstories.\033[0m" % (p.permalink(lang), p.title(lang))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nikola will take care of ending formats itself. (I’ll fix this one.)
Thank you for contributing to Nikola! 🎉 |
The hierachical menu is based on the structure of the stories (permalink).
See: https://groups.google.com/forum/#!topic/nikola-discuss/Ry4LpSMY0Bg