diff --git a/src/pyj/book_list/search.pyj b/src/pyj/book_list/search.pyj index bb3a579121..3115139542 100644 --- a/src/pyj/book_list/search.pyj +++ b/src/pyj/book_list/search.pyj @@ -62,6 +62,7 @@ class SearchPanel: self.initial_load_started = False self.currently_loading = None self.tag_browser_data = None + self.node_id_map = {} def init(self): tb = self.container.querySelector('input[name="search-books"]') @@ -87,11 +88,12 @@ class SearchPanel: self.currently_loading = None if end_type == 'abort': return + parent = self.container.lastChild if parent.lastChild.style.display == 'none': parent.firstChild.style.display = 'none' parent.lastChild.style.display = 'block' - container = parent.lastChild + container = self.tb_container clear(container) def show_error(error_html): @@ -99,48 +101,58 @@ class SearchPanel: container.appendChild(ediv) ediv.innerHTML = '

' + _('Failed to load tag browser data') + '

' + error_html + def process_node(node): + self.node_id_map[node.id] = node + node.data = item_map[node.id] + for child in node.children: + child.parent = node + process_node(child) + if end_type == 'load': try: - self.tag_browser_data = JSON.parse(xhr.responseText) + tag_browser_data = JSON.parse(xhr.responseText) except Exception as err: show_error(err + '') return + item_map = tag_browser_data['item_map'] + self.tag_browser_data = tag_browser_data.root + process_node(self.tag_browser_data) self.render_tag_browser(container, clear_path=True) else: show_error(xhr.error_html) - def render_tag_browser(self, container, clear_path=False): + def node_for_path(self, path): + path = path or self.tag_path + ans = self.tag_browser_data + for child_index in path: + ans = ans.children[child_index] + return ans + + def render_tag_browser(self, container=None, clear_path=False): if clear_path: self.tag_path = [] + container = container or self.tb_container clear(container) set_css(container, padding='1rem', display='flex', flex_wrap='wrap') - parent = self.tag_browser_data.root - detailed_child = None - for child_index, state in self.tag_path: - q = parent.children and parent.children[child_index] - if not q: - break - parent, detailed_child = q, state - if detailed_child is not None and parent.children[detailed_child]: - self.render_child_menu(container, parent.children[detailed_child]) - else: - self.render_children(container, parent.children) + self.render_children(container, self.node_for_path().children) def icon_for_node(self, node): - ans = self.interface_data.icon_map[node.category] or 'column.png' + ans = self.interface_data.icon_map[node.data.category] or 'column.png' return self.interface_data.icon_path + '/' + ans def render_children(self, container, children): - item_map = self.tag_browser_data.item_map - for child in children: - node = item_map[child.id] + def click_handler(func, i): + return def(): + func.call(self, i) + + for i, node in enumerate(children): div = E.div( style="display:flex; align-items: stretch", E.div(class_='tag-name', style='border-right:solid 1px currentColor; padding: 1ex; display:block', E.img(src=self.icon_for_node(node), style='vertical-align:middle; display:inline-block; max-height:4ex'), - '\xa0' + node.name + '\xa0' + node.data.name ), E.div(class_='tag-menu', style='padding: 1ex; display:flex; align-items:center', @@ -148,12 +160,32 @@ class SearchPanel: ) ) set_css(div, max_width='45vw', border='solid 1px currentColor', border_radius='20px', margin='0.5rem', cursor='pointer', overflow='hidden', user_select='none') + div.firstChild.addEventListener('click', click_handler(self.node_clicked, i)) container.appendChild(div) + def search_expression_for_item(self, node): + pass + + def node_clicked(self, i): + node = self.node_for_path().children[i] + if node.children and node.children.length: + self.tag_path.append(i) + self.render_tag_browser() + else: + self.execute_search(self.search_expression_for_item(node)) + @property def container(self): return document.getElementById(self.container_id) + @property + def tb_container(self): + return self.container.lastChild.lastChild + + @property + def search_control(self): + return self.container.querySelector('input[name="search-books"]') + @property def is_visible(self): self.container.style.display == 'block' @@ -162,6 +194,6 @@ class SearchPanel: def is_visible(self, val): self.container.style.display = 'block' if val else 'none' - def execute_search(self): - text = self.container.querySelector('input[name="search-books"]').value or '' + def execute_search(self, text=''): + text = text or self.search_control.value or '' get_boss().ui.books_view.change_search(text)