From 2b7178a08f07e7a1ffa8aa048aefffaf9575072a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 4 Feb 2016 12:13:35 +0530 Subject: [PATCH] More work on CS TB --- src/calibre/srv/metadata.py | 12 ++++--- src/pyj/book_list/search.pyj | 62 ++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/calibre/srv/metadata.py b/src/calibre/srv/metadata.py index 34580d9795..d1b1adf0b9 100644 --- a/src/calibre/srv/metadata.py +++ b/src/calibre/srv/metadata.py @@ -65,7 +65,7 @@ _include_fields = frozenset(Tag.__slots__) - frozenset({ def category_as_json(items, category, display_name, count, tooltip=None, parent=None, is_editable=True, is_gst=False, is_hierarchical=False, is_searchable=True, - is_user_category=False): + is_user_category=False, is_first_letter=False): ans = {'category': category, 'name': display_name, 'is_category':True, 'count':count} if tooltip: ans['tooltip'] = tooltip @@ -81,6 +81,8 @@ def category_as_json(items, category, display_name, count, tooltip=None, parent= ans['is_searchable'] = True if is_user_category: ans['is_user_category'] = True + if is_first_letter: + ans['is_first_letter'] = True item_id = 'c' + str(len(items)) items[item_id] = ans return item_id @@ -93,11 +95,13 @@ def category_item_as_json(x, clear_rating=False): if k == 'original_categories': val = tuple(val) ans[k] = val.copy() if isinstance(val, set) else val + s = ans.get('sort') if x.use_sort_as_name: - ans['name'] = ans['sort'] + ans['name'] = s if x.original_name != ans['name']: ans['original_name'] = x.original_name - ans.pop('sort', None) + if x.use_sort_as_name or not s or s == ans['name']: + ans.pop('sort', None) if clear_rating: del ans['avg_rating'] return ans @@ -300,7 +304,7 @@ def collapse_first_letter(collapse_nodes, items, category_node, cl_list, idx, is node_id = category_as_json( items, items[category_node['id']]['category'], collapse_letter, 0, parent=category_node['id'], is_editable=False, is_gst=is_gst, - is_hierarchical=category_is_hierarchical) + is_hierarchical=category_is_hierarchical, is_first_letter=True) node_parent = {'id':node_id, 'children':[]} category_node['children'].append(node_parent) collapse_nodes.append(node_parent) diff --git a/src/pyj/book_list/search.pyj b/src/pyj/book_list/search.pyj index 5632de9eb3..669a04a54c 100644 --- a/src/pyj/book_list/search.pyj +++ b/src/pyj/book_list/search.pyj @@ -164,8 +164,63 @@ class SearchPanel: div.firstChild.addEventListener('click', click_handler(self.node_clicked, i)) container.appendChild(div) - def search_expression_for_item(self, node): - pass + def search_expression_for_item(self, node, state): + item = node.data + if item.is_searchable is False or not state or state == 'clear': + return '' + + search_state = {'plus':'true', 'plusplus':'.true', 'minus':'false', 'minusminus':'.false'}[state] + + if item.is_category: + category = item.category + + if item.is_first_letter: + letters_seen = {} + for child in node.children: + if child.data.sort: + letters_seen[child.data.sort[0]] = True + letters_seen = Object.keys(letters_seen) + if letters_seen.length: + charclass = letters_seen.join('') + if category == 'authors': + expr = str.format(r'author_sort:"~(^[{0}])|(&\s*[{0}])"', charclass) + elif category == 'series': + expr = str.format(r'series_sort:"~^[{0}]"', charclass) + else: + expr = str.format(r'{0}:"~^[{1}]"', category, charclass) + else: + expr = str.format('{}:false', category) + + elif category == 'news': + expr = str.format('tags:"={}"', item.name) + + else: + return str.format('{}:{}', category, search_state) + + if 'false' in search_state: + expr = '(not ' + expr + ')' + return expr + + category = 'tags' if item.category == 'news' else item.category + if item.name and item.name[0] == '★': + # Assume ratings + expr = str.format('{}:{}', category, item.name.length) + else: + fm = self.interface_data.field_metadata[item.category] + suffix = ':' if fm and fm.is_csp else '' + name = item.name or item.sort + if not name: + return '' + name = str.replace(name, '"', r'\"') + if name[0] == '.': + name = '.' + name + if search_state == 'plusplus' or search_state == 'minusminus': + name = '.' + name + expr = str.format('{}:"={}{}"', category, name, suffix) + + if 'false' in search_state: + expr = '(not ' + expr + ')' + return expr def node_clicked(self, i): node = self.node_for_path().children[i] @@ -173,7 +228,8 @@ class SearchPanel: self.tag_path.append(i) self.render_tag_browser() else: - self.execute_search(self.search_expression_for_item(node)) + expr = self.search_expression_for_item(node, 'plus') + self.execute_search(expr) @property def container(self):