button.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. from functools import total_ordering
  2. from django.forms.utils import flatatt
  3. from django.template.loader import render_to_string
  4. from django.utils.functional import cached_property
  5. from django.utils.html import format_html
  6. from wagtail import hooks
  7. @total_ordering
  8. class Button:
  9. show = True
  10. def __init__(
  11. self, label, url, classes=set(), icon_name=None, attrs={}, priority=1000
  12. ):
  13. self.label = label
  14. self.url = url
  15. self.classes = classes
  16. self.icon_name = icon_name
  17. self.attrs = attrs.copy()
  18. self.priority = priority
  19. def render(self):
  20. attrs = {
  21. "href": self.url,
  22. "class": " ".join(sorted(self.classes)),
  23. "title": self.label,
  24. }
  25. attrs.update(self.attrs)
  26. return format_html("<a{}>{}</a>", flatatt(attrs), self.label)
  27. def __str__(self):
  28. return self.render()
  29. def __repr__(self):
  30. return "<Button: {}>".format(self.label)
  31. def __lt__(self, other):
  32. if not isinstance(other, Button):
  33. return NotImplemented
  34. return (self.priority, self.label) < (other.priority, other.label)
  35. def __eq__(self, other):
  36. if not isinstance(other, Button):
  37. return NotImplemented
  38. return (
  39. self.label == other.label
  40. and self.url == other.url
  41. and self.classes == other.classes
  42. and self.attrs == other.attrs
  43. and self.priority == other.priority
  44. )
  45. # Base class for all listing buttons
  46. # This is also used by SnippetListingButton defined in wagtail.snippets.widgets
  47. class ListingButton(Button):
  48. def __init__(self, label, url, classes=set(), **kwargs):
  49. classes = {"button", "button-small", "button-secondary"} | set(classes)
  50. super().__init__(label, url, classes=classes, **kwargs)
  51. class PageListingButton(ListingButton):
  52. pass
  53. class BaseDropdownMenuButton(Button):
  54. def __init__(self, *args, **kwargs):
  55. super().__init__(*args, url=None, **kwargs)
  56. @cached_property
  57. def dropdown_buttons(self):
  58. raise NotImplementedError
  59. def get_context_data(self):
  60. return {
  61. "buttons": self.dropdown_buttons,
  62. "label": self.label,
  63. "title": self.attrs.get("title"),
  64. "is_parent": self.is_parent,
  65. }
  66. def render(self):
  67. return render_to_string(self.template_name, self.get_context_data())
  68. class ButtonWithDropdown(BaseDropdownMenuButton):
  69. template_name = "wagtailadmin/pages/listing/_button_with_dropdown.html"
  70. def __init__(self, *args, **kwargs):
  71. self.button_classes = kwargs.pop("button_classes", set())
  72. self.buttons_data = kwargs.pop("buttons_data", [])
  73. super().__init__(*args, **kwargs)
  74. def get_context_data(self):
  75. context = super().get_context_data()
  76. context["button_classes"] = self.button_classes
  77. context["classes"] = self.classes
  78. return context
  79. @cached_property
  80. def dropdown_buttons(self):
  81. return [Button(**button) for button in self.buttons_data]
  82. class ButtonWithDropdownFromHook(BaseDropdownMenuButton):
  83. template_name = "wagtailadmin/pages/listing/_button_with_dropdown.html"
  84. def __init__(
  85. self, label, hook_name, page, page_perms, is_parent, next_url=None, **kwargs
  86. ):
  87. self.hook_name = hook_name
  88. self.page = page
  89. self.page_perms = page_perms
  90. self.is_parent = is_parent
  91. self.next_url = next_url
  92. super().__init__(label, **kwargs)
  93. @property
  94. def show(self):
  95. return bool(self.dropdown_buttons)
  96. @cached_property
  97. def dropdown_buttons(self):
  98. button_hooks = hooks.get_hooks(self.hook_name)
  99. buttons = []
  100. for hook in button_hooks:
  101. buttons.extend(
  102. hook(self.page, self.page_perms, self.is_parent, self.next_url)
  103. )
  104. buttons.sort()
  105. return buttons