Coverage for src / ptf_tools / views / components / breadcrumb.py: 29%

63 statements  

« prev     ^ index     » next       coverage.py v7.13.2, created at 2026-08-03 13:45 +0000

1from __future__ import annotations 

2 

3from typing import TYPE_CHECKING 

4 

5from django.urls import reverse 

6from django.utils.translation import gettext as translate_text 

7from django.utils.translation import gettext_lazy as _ 

8from ptf.models import ResourceVisitor 

9from ptf.views.components.breadcrumb import ( 

10 Breadcrumb, 

11 BreadcrumbItem, 

12 get_next_article, 

13 get_previous_article, 

14) 

15 

16if TYPE_CHECKING: 

17 from ptf.models import Article, Collection, Container, Resource 

18 

19 

20def get_trammel_base_breadcrumb() -> Breadcrumb: 

21 return Breadcrumb( 

22 items=[ 

23 BreadcrumbItem( 

24 title=_("Home"), 

25 url=reverse("home"), 

26 icon_class="bi-house", 

27 ) 

28 ] 

29 ) 

30 

31 

32def get_trammel_breadcrumb(resource: Resource) -> Breadcrumb: 

33 visitor = TrammelBreadcrumbVisitor() 

34 return resource.accept(visitor) 

35 

36 

37class TrammelBreadcrumbVisitor(ResourceVisitor): 

38 def __init__(self): 

39 super().__init__() 

40 self.crumb = get_trammel_base_breadcrumb() 

41 

42 def visit(self, resource): 

43 method = getattr(self, f"visit_{resource.classname.lower()}") 

44 return method(resource) 

45 

46 def visit_collection(self, collection: Collection) -> Breadcrumb: 

47 self._add_collection_item(collection) 

48 return self.crumb 

49 

50 def visit_container(self, container: Container) -> Breadcrumb: 

51 collection = container.get_top_collection() 

52 

53 self._add_collection_item(collection) 

54 self._add_container_item(container) 

55 

56 return self.crumb 

57 

58 def visit_article(self, article: Article) -> Breadcrumb: 

59 collection = article.get_top_collection() 

60 container = article.get_container() 

61 

62 self._add_collection_item(collection) 

63 

64 if container is not None: 

65 self._add_container_item(container) 

66 

67 self._add_article_item(article) 

68 self._set_next_previous_article_items(article) 

69 

70 return self.crumb 

71 

72 def _add_collection_item(self, collection: Collection) -> None: 

73 self.crumb.add_item( 

74 title=collection.title_html or collection.title_tex or collection.pid, 

75 url=self._collection_url(collection), 

76 html=True, 

77 ) 

78 

79 def _add_container_item(self, container: Container) -> None: 

80 self.crumb.add_item( 

81 title=self._container_title(container), 

82 url=self._container_url(container), 

83 html=True, 

84 ) 

85 

86 def _add_article_item(self, article: Article) -> None: 

87 self.crumb.add_item( 

88 title=article.get_breadcrumb_page_text(), 

89 url=article.get_absolute_url(), 

90 html=True, 

91 ) 

92 

93 def _set_next_previous_article_items(self, article: Article) -> None: 

94 next_article = get_next_article(article) 

95 if next_article is not None: 

96 self.crumb.nextItem = BreadcrumbItem( 

97 title=translate_text("Suivant"), 

98 url=next_article.get_absolute_url(), 

99 ) 

100 

101 previous_article = get_previous_article(article) 

102 if previous_article is not None: 

103 self.crumb.previousItem = BreadcrumbItem( 

104 title=translate_text("Précédent"), 

105 url=previous_article.get_absolute_url(), 

106 ) 

107 

108 def _collection_url(self, collection: Collection) -> str: 

109 return reverse("collection-detail", kwargs={"pid": collection.pid}) 

110 

111 def _container_url(self, container: Container) -> str: 

112 return reverse("issue-items", kwargs={"pid": container.pid}) 

113 

114 def _container_title(self, container: Container) -> str: 

115 if container.title_html: 

116 return container.title_html 

117 

118 if container.number: 

119 return f"no. {container.number}" 

120 

121 if container.volume: 

122 return f"Volume {container.volume}" 

123 

124 if container.year_str: 

125 return container.year_str 

126 

127 return container.pid