From 47176b8975a82e65ad8d8ac06aebb06609b6786b Mon Sep 17 00:00:00 2001 From: UlrichB22 <97119703+UlrichB22@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:32:17 +0100 Subject: [PATCH] Add macro TitleIndex --- src/moin/macros/ItemList.py | 5 +- src/moin/macros/RandomItem.py | 5 +- src/moin/macros/TitleIndex.py | 35 ++++++++ src/moin/macros/_base.py | 150 +++++++++++++++++++++++++--------- 4 files changed, 152 insertions(+), 43 deletions(-) create mode 100644 src/moin/macros/TitleIndex.py diff --git a/src/moin/macros/ItemList.py b/src/moin/macros/ItemList.py index 73ac2e182..c5eff71fa 100644 --- a/src/moin/macros/ItemList.py +++ b/src/moin/macros/ItemList.py @@ -1,4 +1,5 @@ # Copyright: 2019 MoinMoin:KentWatsen +# Copyright: 2024 MoinMoin:UlrichB # License: GNU GPL v2 (or any later version), see LICENSE.txt for details. """ @@ -67,7 +68,7 @@ from moin.i18n import _ from moin.utils.tree import moin_page from moin.utils.interwiki import split_fqname -from moin.macros._base import MacroPageLinkListBase +from moin.macros._base import MacroPageLinkListBase, get_item_names class Macro(MacroPageLinkListBase): @@ -131,7 +132,7 @@ def macro(self, content, arguments, page_url, alternative): return admonition # process subitems - children = self.get_item_names(item, startswith=startswith, skiptag=skiptag) + children = get_item_names(item, startswith=startswith, skiptag=skiptag) if regex: try: regex_re = re.compile(regex, re.IGNORECASE) diff --git a/src/moin/macros/RandomItem.py b/src/moin/macros/RandomItem.py index f334476e7..b560c87ca 100644 --- a/src/moin/macros/RandomItem.py +++ b/src/moin/macros/RandomItem.py @@ -1,5 +1,6 @@ # Copyright: 2000 Juergen Hermann # Copyright: 2008-2011 MoinMoin:ThomasWaldmann +# Copyright: 2024 MoinMoin:UlrichB # License: GNU GPL v2 (or any later version), see LICENSE.txt for details. """ @@ -13,7 +14,7 @@ from moin.utils.iri import Iri from moin.utils.tree import moin_page, xlink from moin.items import Item -from moin.macros._base import MacroPageLinkListBase +from moin.macros._base import MacroPageLinkListBase, get_item_names from moin.storage.middleware.protecting import AccessDenied random.seed() @@ -26,7 +27,7 @@ def macro(self, content, arguments, page_url, alternative): else: item_count = 1 - all_item_names = self.get_item_names() + all_item_names = get_item_names() # Now select random item from the full list, and if it exists and # we can read it, save. diff --git a/src/moin/macros/TitleIndex.py b/src/moin/macros/TitleIndex.py new file mode 100644 index 000000000..343a8b45b --- /dev/null +++ b/src/moin/macros/TitleIndex.py @@ -0,0 +1,35 @@ +# Copyright: 2024 MoinMoin:UlrichB +# License: GNU GPL v2 (or any later version), see LICENSE.txt for details. + +""" +TitleIndex - generates a list of links for the namespace of the current item, grouped by initials + +Parameters: + None + +Usage: + <> +""" + +from moin.macros._base import MacroMultiLinkListBase, get_item_names +from moin.i18n import _ +from moin.utils.tree import moin_page +from moin.utils.interwiki import split_fqname + + +class Macro(MacroMultiLinkListBase): + def macro(self, content, arguments, page_url, alternative): + # get namespace of current item + namespace = split_fqname(str(page_url.path)).namespace + + if arguments: + raise ValueError(_("TitleList macro does not have any arguments.")) + + children = get_item_names(namespace) + if not children: + empty_list = moin_page.list(attrib={moin_page.item_label_generate: 'unordered'}) + item_body = moin_page.list_item_body(children=[_("")]) + empty_list.append(moin_page.list_item(children=[item_body])) + return empty_list + + return self.create_multi_pagelink_list(children, namespace) diff --git a/src/moin/macros/_base.py b/src/moin/macros/_base.py index f049b092e..e9107d85e 100644 --- a/src/moin/macros/_base.py +++ b/src/moin/macros/_base.py @@ -1,4 +1,5 @@ # Copyright: 2008 MoinMoin:BastianBlank +# Copyright: 2024 MoinMoin:UlrichB # License: GNU GPL v2 (or any later version), see LICENSE.txt for details. """ @@ -15,6 +16,51 @@ from moin.constants.keys import TAGS +def get_item_names(name='', startswith='', kind='files', skiptag=''): + """ + For the specified item, return the fullname of matching descendents. + + Input: + + name: the name of the item to get. If '' is passed, then the + top-level item is used. + + startwith: a substring the matching pages must begin with. If no + value is specified, then all pages are returned. + + kind: the kind of page to return. Valid values include: + + files: decendents that do not contain decendents. (default) + dirs: decendents that contain decendents. + both: both 'files' and 'dirs', with duplicates removed. + + skiptag: skip items having this tag + + Output: + + A List of descendent items using their "fullname" value + """ + try: + item = Item.create(name) + except AccessDenied: + abort(403) + dirs, files = item.get_index(startswith) + item_names = [] + if not kind or kind == "files" or kind == "both": + for item in files: + if skiptag and TAGS in item.meta and skiptag in item.meta[TAGS]: + continue + item_names.append(item.fullname) + if kind == "dirs" or kind == "both": + for item in dirs: + if skiptag and skiptag in item.meta[TAGS]: + continue + item_names.append(item.fullname) + if kind == "both": + item_names = list(set(item_names)) # remove duplicates + return item_names + + class MacroBase: """ Macro base class. @@ -96,10 +142,12 @@ def create_pagelink_list(self, pagenames, ordered=False, display="FullPath"): uppercase character. skiptag : skip items with this tag ItemTitle : Use the title from the first header in the linked page *not implemented - """ + """ page_list = moin_page.list(attrib={moin_page.item_label_generate: ordered and 'ordered' or 'unordered'}) + for pagename in pagenames: + fqname = pagename.fullname # This link can never reach pagelinks url = str(iri.Iri(scheme='wiki', authority='', path='/' + fqname)) @@ -128,51 +176,75 @@ def create_pagelink_list(self, pagenames, ordered=False, display="FullPath"): item_body = moin_page.list_item_body(children=[pagelink]) item = moin_page.list_item(children=[item_body]) page_list.append(item) - return page_list - - def get_item_names(self, name='', startswith='', kind='files', skiptag=''): - """ - For the specified item, return the fullname of matching descendents. - Input: - - name: the name of the item to get. If '' is passed, then the - top-level item is used. - - startwith: a substring the matching pages must begin with. If no - value is specified, then all pages are returned. + return page_list - kind: the kind of page to return. Valid values include: - files: decendents that do not contain decendents. (default) - dirs: decendents that contain decendents. - both: both 'files' and 'dirs', with duplicates removed. +class MacroMultiLinkListBase(MacroBlockBase): + def create_multi_pagelink_list(self, itemnames, namespace): + """ Creates an ET with a list of itemlinks from a list of itemnames + grouped by initials. - skiptag: skip items having this tag + Parameters: - Output: + itemnames: a list of items, each being like a flask request.path[1:] - A List of descendent items using their "fullname" value + namespace: Namespace of items """ - try: - item = Item.create(name) - except AccessDenied: - abort(403) - dirs, files = item.get_index(startswith) - item_names = [] - if not kind or kind == "files" or kind == "both": - for item in files: - if skiptag and TAGS in item.meta and skiptag in item.meta[TAGS]: - continue - item_names.append(item.fullname) - if kind == "dirs" or kind == "both": - for item in dirs: - if skiptag and skiptag in item.meta[TAGS]: - continue - item_names.append(item.fullname) - if kind == "both": - item_names = list(set(item_names)) # remove duplicates - return item_names + + result_body = [] + initials_linklist = [] + initial_letter = ' ' + + if namespace == '': + namespace_name = _("Namespace '%(name)s' ", name='default') + pos_namespace_cut = 0 + else: + namespace_name = _("Namespace '%(name)s' ", name=namespace) + pos_namespace_cut = len(namespace) + 1 + + item_list = moin_page.list(attrib={moin_page.item_label_generate: 'unordered'}) + initials_link = moin_page.a(attrib={xlink.href: '#idx-top'}, children=['top', ]) + initials_linklist.extend([initials_link, moin_page.strong(children=[' | ', ])]) + + for itemname in itemnames: + if not itemname.value.startswith(initial_letter): + # generate header line with initial + initial_letter = itemname.value[0] + result_body.append(item_list) # finish item_list for last initial and initialize new item_list + item_list = moin_page.list(attrib={moin_page.item_label_generate: 'unordered'}) + + header_with_anchor = moin_page.span( + attrib={moin_page.class_: "moin-big", moin_page.id: 'idx-' + initial_letter}, + children=[initial_letter, + moin_page.a(attrib={moin_page.class_: "moin-align-right", xlink.href: '#idx-top'}, + children=['^', ])]) + result_body.append(header_with_anchor) + initials_link = moin_page.a(attrib={xlink.href: '#idx-' + initial_letter}, children=[initial_letter]) + initials_linklist.extend([initials_link, moin_page.strong(children=[' | ',])]) + + # build and add itemname link + fqname = itemname.fullname + url = str(iri.Iri(scheme='wiki', authority='', path='/' + fqname)) + linkname = fqname[pos_namespace_cut:] + pagelink = moin_page.a(attrib={xlink.href: url}, children=[linkname]) + item_body = moin_page.list_item_body(children=[pagelink]) + item = moin_page.list_item(children=[item_body]) + item_list.append(item) + + result_body.append(item_list) # finish item_list for last initial + + # Add a list of links for each used initial at top and bottom of the index + initials_begin = moin_page.span(attrib={moin_page.id: "idx-top", moin_page.class_: "moin-align-left"}, + children=[_("Index of %(what)s", what=namespace_name), ]) + initials_link_end = moin_page.a(attrib={xlink.href: '#idx-bottom'}, children=['bottom', ]) + initials_linklist.append(initials_link_end) + initials_links_span = moin_page.span(attrib={moin_page.class_: "moin-align-right"}, children=initials_linklist) + result_body.insert(0, moin_page.p(children=[initials_begin, initials_links_span])) + initials_end = moin_page.span( + attrib={moin_page.id: "idx-bottom", moin_page.class_: "moin-align-left"}, children=".") + result_body.append(moin_page.p(children=[initials_end, initials_links_span])) + return moin_page.body(children=result_body) class MacroNumberPageLinkListBase(MacroBlockBase):