Skip to content

Commit d47e097

Browse files
Merge pull request #76 from discord-modmail/fix/paginator-options
fix: paginator can now not use an embed
2 parents 7347f59 + 81b5692 commit d47e097

File tree

2 files changed

+59
-48
lines changed

2 files changed

+59
-48
lines changed

modmail/utils/pagination.py

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
JUMP_LAST_LABEL = " \u276f\u276f " # >>
3232
STOP_PAGINATE_EMOJI = "\u274c" # [:x:] This is an emoji, which is treated differently from the above
3333

34+
NO_EMBED_FOOTER_BUMP = 15
35+
36+
_AUTOGENERATE = object()
37+
38+
3439
logger: ModmailLogger = logging.getLogger(__name__)
3540

3641

@@ -57,13 +62,14 @@ def __init__(
5762
contents: Union[List[str], str],
5863
/,
5964
source_message: Optional[discord.Message] = None,
60-
embed: Embed = None,
65+
embed: Union[Embed, bool, None] = _AUTOGENERATE,
6166
timeout: float = 180,
6267
*,
6368
footer_text: str = None,
6469
prefix: str = "```",
6570
suffix: str = "```",
6671
max_size: int = 2000,
72+
title: str = None,
6773
linesep: str = "\n",
6874
only_users: Optional[List[Union[discord.Object, discord.abc.User]]] = None,
6975
only_roles: Optional[List[Union[discord.Object, discord.Role]]] = None,
@@ -75,14 +81,33 @@ def __init__(
7581
If source message is provided and only_users is NOT provided, the paginator will respond
7682
to the author of the source message. To override this, pass an empty list to `only_users`.
7783
84+
By default, an embed is created. However, a custom embed can
85+
be passed, or None can be passed to not use an embed.
7886
"""
7987
self.index = 0
8088
self._pages: List[str] = []
8189
self.prefix = prefix
8290
self.suffix = suffix
8391
self.max_size = max_size
8492
self.linesep = linesep
85-
self.embed = embed or Embed()
93+
if embed is _AUTOGENERATE or embed is True:
94+
self.embed = Embed()
95+
else:
96+
if embed is False:
97+
embed = None
98+
self.embed = embed
99+
100+
# used if embed is None
101+
self.content = ""
102+
if self.embed is None:
103+
self.title = title
104+
# need to set the max_size down a few to be able to set a "footer"
105+
# page indicator is "page xx of xx"
106+
self.max_size -= NO_EMBED_FOOTER_BUMP + len(self.title or "")
107+
if self.title is not None:
108+
self.max_size -= len(title)
109+
if footer_text is not None:
110+
self.max_size -= len(footer_text) + 1
86111

87112
# temporary to support strings as contents. This will be changed when we added wrapping.
88113
if isinstance(contents, str):
@@ -116,8 +141,8 @@ def __init__(
116141

117142
# set footer to embed.footer if embed is set
118143
# this is because we will be modifying the footer of this embed
119-
if embed is not None:
120-
if not isinstance(embed.footer, EmbedProxy) and footer_text is None:
144+
if self.embed is not None:
145+
if not isinstance(self.embed.footer, EmbedProxy) and footer_text is None:
121146
footer_text = embed.footer
122147
self.footer_text = footer_text
123148
self.clear()
@@ -140,7 +165,7 @@ async def paginate(
140165
source_message: discord.Message = None,
141166
/,
142167
timeout: float = 180,
143-
embed: Embed = None,
168+
embed: Embed = _AUTOGENERATE,
144169
*,
145170
footer_text: str = None,
146171
only: Optional[discord.abc.User] = None,
@@ -149,6 +174,7 @@ async def paginate(
149174
prefix: str = "",
150175
suffix: str = "",
151176
max_size: int = 4000,
177+
title: str = None,
152178
linesep: str = "\n",
153179
only_users: Optional[List[Union[discord.Object, discord.abc.User]]] = None,
154180
only_roles: Optional[List[Union[discord.Object, discord.abc.Role]]] = None,
@@ -167,6 +193,7 @@ async def paginate(
167193
prefix=prefix,
168194
suffix=suffix,
169195
max_size=max_size,
196+
title=title,
170197
linesep=linesep,
171198
only_users=only_users,
172199
only_roles=only_roles,
@@ -178,18 +205,24 @@ async def paginate(
178205
channel = source_message.channel
179206

180207
paginator.update_states()
181-
paginator.embed.description = paginator.pages[paginator.index]
182208
# if there's only one page, don't send the view
183209
if len(paginator.pages) < 2:
184-
await channel.send(embeds=[paginator.embed])
210+
if paginator.embed:
211+
await channel.send(embeds=[paginator.embed])
212+
else:
213+
await channel.send(content=paginator.content)
214+
185215
return
186216

187217
if len(paginator.pages) < (show_jump_buttons_min_pages or 3):
188218
for item in paginator.children:
189219
if getattr(item, "custom_id", None) in ["pag_jump_first", "pag_jump_last"]:
190220
paginator.remove_item(item)
191221

192-
msg: discord.Message = await channel.send(embeds=[paginator.embed], view=paginator)
222+
if paginator.embed is None:
223+
msg: discord.Message = await channel.send(content=paginator.content, view=paginator)
224+
else:
225+
msg: discord.Message = await channel.send(embeds=[paginator.embed], view=paginator)
193226

194227
await paginator.wait()
195228
await msg.edit(view=None)
@@ -212,15 +245,6 @@ async def interaction_check(self, interaction: Interaction) -> bool:
212245
)
213246
return False
214247

215-
def get_footer(self) -> str:
216-
"""Returns the footer text."""
217-
self.embed.description = self._pages[self.index]
218-
page_indicator = f"Page {self.index+1}/{len(self._pages)}"
219-
footer_txt = (
220-
f"{self.footer_text} ({page_indicator})" if self.footer_text is not None else page_indicator
221-
)
222-
return footer_txt
223-
224248
def update_states(self) -> None:
225249
"""
226250
Disable specific components depending on paginator page and length.
@@ -230,7 +254,20 @@ def update_states(self) -> None:
230254
if the paginator is on the last page, the jump last/move forward buttons will be disabled.
231255
"""
232256
# update the footer
233-
self.embed.set_footer(text=self.get_footer())
257+
page_indicator = f"Page {self.index+1}/{len(self._pages)}"
258+
if self.footer_text:
259+
footer_text = f"{self.footer_text} ({page_indicator})"
260+
else:
261+
footer_text = page_indicator
262+
263+
if self.embed is None:
264+
self.content = (self.title or "") + "\n"
265+
self.content += self._pages[self.index]
266+
self.content += "\n" + footer_text
267+
268+
else:
269+
self.embed.description = self._pages[self.index]
270+
self.embed.set_footer(text=footer_text)
234271

235272
# determine if the jump buttons should be enabled
236273
more_than_two_pages = len(self._pages) > 2
@@ -264,7 +301,10 @@ async def send_page(self, interaction: Interaction) -> None:
264301
"""Send new page to discord, after updating the view to have properly disabled buttons."""
265302
self.update_states()
266303

267-
await interaction.message.edit(embed=self.embed, view=self)
304+
if self.embed:
305+
await interaction.message.edit(embed=self.embed, view=self)
306+
else:
307+
await interaction.message.edit(content=self.content, view=self)
268308

269309
@ui.button(label=JUMP_FIRST_LABEL, custom_id="pag_jump_first", style=ButtonStyle.primary)
270310
async def go_first(self, _: Button, interaction: Interaction) -> None:
Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import List, Union
2-
31
import pytest
42

53
from modmail.utils.pagination import ButtonPaginator
@@ -11,30 +9,3 @@ async def test_paginator_init() -> None:
119
content = ["content"]
1210
paginator = ButtonPaginator(content, prefix="", suffix="", linesep="")
1311
assert paginator.pages == content
14-
15-
16-
@pytest.mark.asyncio
17-
@pytest.mark.parametrize(
18-
"content, footer_text",
19-
[
20-
(["5"], "Snap, crackle, pop"),
21-
(["Earthly"], "world"),
22-
("There are no plugins installed.", None),
23-
],
24-
)
25-
async def test_paginator_footer(content: Union[str, List[str]], footer_text: str) -> None:
26-
"""Test the paginator footer matches what is passed."""
27-
pag = ButtonPaginator(content, footer_text=footer_text)
28-
print("index:", pag.index)
29-
print("page len: ", len(pag.pages))
30-
assert pag.footer_text == footer_text
31-
if isinstance(content, str):
32-
content = [content]
33-
34-
print(pag.get_footer())
35-
if footer_text is not None:
36-
assert pag.get_footer().endswith(f"{len(content)})")
37-
assert pag.get_footer().startswith(footer_text)
38-
39-
else:
40-
assert pag.get_footer().endswith(f"{len(content)}")

0 commit comments

Comments
 (0)