comparison libervia/web/pages/_browser/jid_search.py @ 1548:66aa6e140ebb

browser: make `jid_search` more generic: rel 423
author Goffi <goffi@goffi.org>
date Wed, 09 Aug 2023 00:22:16 +0200
parents 7f3f5ae7d65a
children e47c24204449
comparison
equal deleted inserted replaced
1547:383e1fee29f6 1548:66aa6e140ebb
1 import json
2 from urllib.parse import quote, urljoin
3
1 from bridge import AsyncBridge as Bridge 4 from bridge import AsyncBridge as Bridge
2 from browser import aio, console as log, window 5 from browser import aio, console as log, window
3 from cache import cache 6 from cache import cache
4 import json 7 from template import Template
5 8
6 log.warning = log.warn 9 log.warning = log.warn
7 profile = window.profile or "" 10 profile = window.profile or ""
8 bridge = Bridge() 11 bridge = Bridge()
9 12
10
11 class JidSearch: 13 class JidSearch:
12 14
13 def __init__(self, search_elt, callback, empty_cb=None): 15 def __init__(
16 self,
17 search_elt,
18 container_elt=None,
19 filter_cb=None,
20 empty_cb=None,
21 get_url=None,
22 click_cb=None
23 ):
24 """Initialize the JidSearch instance
25
26 @param search_elt: The HTML <input> element for search
27 @param container_elt: The HTML container to display the search results
28 @param filter_cb: The callback to filter the search results
29 @param empty_cb: The callback when the search box is empty
30 @param get_url: The function to get URL for each entity in the search result
31 @param click_cb: The function to handle the click event on each entity in the
32 search result
33 """
34 self.search_item_tpl = Template("components/search_item.html")
14 self.search_elt = search_elt 35 self.search_elt = search_elt
15 self.search_elt.bind("input", self.on_search_input) 36 self.search_elt.bind("input", self.on_search_input)
16 self.last_query = None 37 self.last_query = None
17 self.current_query = None 38 self.current_query = None
18 self.callback = callback 39 self.container_elt = container_elt
19 self.empty_cb = empty_cb 40
41 if click_cb is not None and get_url is None:
42 self.get_url = lambda _: "#"
43 else:
44 self.get_url = get_url if get_url is not None else self.default_get_url
45 self.click_cb = click_cb
46
47 if filter_cb is None:
48 if container_elt is None:
49 raise ValueError("container_elt must be set if filter_cb is not set")
50 filter_cb = self.show_items
51 self.filter_cb = filter_cb
52
53 self.empty_cb = empty_cb or self.on_empty_search
54
20 current_search = search_elt.value.strip() or None 55 current_search = search_elt.value.strip() or None
21 if current_search is not None: 56 if current_search is not None:
22 aio.run(self.perform_search(current_search)) 57 aio.run(self.perform_search(current_search))
23 58
59 def default_get_url(self, item):
60 """Default method to get the URL for a given entity
61
62 @param item: The item (entity) for which the URL is required
63 """
64 return urljoin(f"{window.location.href}/", quote(item["entity"]))
65
66 def show_items(self, items):
67 """Display the search items in the specified container
68
69 @param items: The list of search items to be displayed
70 """
71 assert self.container_elt is not None
72 self.container_elt.clear()
73 for item in items:
74 search_item_elt = self.search_item_tpl.get_elt({
75 "url": self.get_url(item),
76 "item": item,
77 "identities": cache.identities
78 })
79 if self.click_cb is not None:
80 search_item_elt.bind('click', lambda evt, item=item: self.click_cb(item))
81 self.container_elt <= search_item_elt
82
24 def on_search_input(self, evt): 83 def on_search_input(self, evt):
84 """Handle the 'input' event for the search element
85
86 @param evt: The event object
87 """
25 search_text = evt.target.value.strip() 88 search_text = evt.target.value.strip()
26 if not search_text and self.empty_cb is not None: 89 if not search_text:
27 self.empty_cb() 90 self.empty_cb()
28 elif len(search_text) > 2: 91 elif len(search_text) > 2:
29 aio.run(self.perform_search(search_text)) 92 aio.run(self.perform_search(search_text))
30 93
31 async def perform_search(self, query): 94 async def perform_search(self, query):
95 """Perform the search operation for a given query
96
97 @param query: The search query
98 """
32 if self.current_query is None: 99 if self.current_query is None:
33 log.debug(f"performing search: {query=}") 100 log.debug(f"performing search: {query=}")
34 self.current_query = query 101 self.current_query = query
35 jid_items = json.loads(await bridge.jid_search(query, "")) 102 jid_items = json.loads(await bridge.jid_search(query, ""))
36 await cache.fill_identities(i["entity"] for i in jid_items) 103 await cache.fill_identities(i["entity"] for i in jid_items)
39 self.current_query = None 106 self.current_query = None
40 current_query = self.search_elt.value.strip() 107 current_query = self.search_elt.value.strip()
41 if current_query != query: 108 if current_query != query:
42 await self.perform_search(current_query) 109 await self.perform_search(current_query)
43 return 110 return
44 self.callback(jid_items) 111 self.filter_cb(jid_items)
112
113 def on_empty_search(self):
114 """Handle the situation when the search box is empty"""
115 assert self.container_elt is not None
116 items = [
117 {
118 "entity": jid_,
119 "groups": data["groups"]
120 }
121 for jid_, data in cache.roster.items()
122 ]
123 self.show_items(items)