mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement searching the TOC view
This commit is contained in:
parent
53649d9cf3
commit
48ba6080ea
@ -24,6 +24,9 @@ def get_color(name):
|
|||||||
'list-hover-background': DARK,
|
'list-hover-background': DARK,
|
||||||
'list-hover-foreground': LIGHT,
|
'list-hover-foreground': LIGHT,
|
||||||
|
|
||||||
|
# Tree colors
|
||||||
|
'tree-highlight-item': LIGHT_DARKER,
|
||||||
|
|
||||||
# Button colors
|
# Button colors
|
||||||
'button-start': DARK,
|
'button-start': DARK,
|
||||||
'button-end': '#49423B',
|
'button-end': '#49423B',
|
||||||
|
@ -5,7 +5,8 @@ from __python__ import hash_literals
|
|||||||
from dom import set_css, svgicon
|
from dom import set_css, svgicon
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from widgets import create_tree
|
from modals import error_dialog
|
||||||
|
from widgets import create_tree, find_text_in_tree, scroll_tree_item_into_view
|
||||||
|
|
||||||
def create_toc_tree(toc, onclick):
|
def create_toc_tree(toc, onclick):
|
||||||
|
|
||||||
@ -16,6 +17,30 @@ def create_toc_tree(toc, onclick):
|
|||||||
|
|
||||||
return create_tree(toc, populate_data, onclick)
|
return create_tree(toc, populate_data, onclick)
|
||||||
|
|
||||||
|
def do_search(text, container):
|
||||||
|
a = find_text_in_tree(container, text)
|
||||||
|
if not text:
|
||||||
|
return
|
||||||
|
if not a:
|
||||||
|
return error_dialog(_('No matches found'), _(
|
||||||
|
'The text "{}" was not found in the Table of Contents').format(text))
|
||||||
|
scroll_tree_item_into_view(a)
|
||||||
|
|
||||||
|
def on_input_keydown(event):
|
||||||
|
if event.keyCode is 13: # Enter
|
||||||
|
event.preventDefault(), event.stopPropagation()
|
||||||
|
text = event.target.value
|
||||||
|
event.target.nextSibling.focus()
|
||||||
|
container = event.target.parentNode.parentNode.firstChild.nextSibling
|
||||||
|
do_search(text, container)
|
||||||
|
|
||||||
|
def on_search_click(event):
|
||||||
|
if event.button is 0:
|
||||||
|
event.preventDefault(), event.stopPropagation()
|
||||||
|
text = event.currentTarget.previousSibling.value
|
||||||
|
container = event.currentTarget.parentNode.parentNode.firstChild.nextSibling
|
||||||
|
do_search(text, container)
|
||||||
|
|
||||||
def create_toc_panel(book, container, onclick, onclose):
|
def create_toc_panel(book, container, onclick, onclose):
|
||||||
container.appendChild(E.div(
|
container.appendChild(E.div(
|
||||||
style='display: flex; justify-content: space-between; padding: 1ex 1em; border-bottom: solid 1px currentColor',
|
style='display: flex; justify-content: space-between; padding: 1ex 1em; border-bottom: solid 1px currentColor',
|
||||||
@ -29,3 +54,14 @@ def create_toc_panel(book, container, onclick, onclose):
|
|||||||
set_css(container, display='flex', flex_direction='column')
|
set_css(container, display='flex', flex_direction='column')
|
||||||
set_css(toc_panel, flex_grow='10')
|
set_css(toc_panel, flex_grow='10')
|
||||||
container.appendChild(toc_panel)
|
container.appendChild(toc_panel)
|
||||||
|
|
||||||
|
container.appendChild(E.div(
|
||||||
|
style='margin: 1ex 1em; display: flex;',
|
||||||
|
E.input(
|
||||||
|
type='search', autosave='search-toc-in-calibre-book-reader', name='toc-serach',
|
||||||
|
autocomplete='on', inputmode='latin',
|
||||||
|
title=_('Search Table of Contents'), placeholder=_('Search Table of Contents'), spellcheck='false',
|
||||||
|
style="flex-grow: 10; margin-right: 0.5em", onkeydown=on_input_keydown,
|
||||||
|
),
|
||||||
|
E.div(class_='simple-link', svgicon('search'), onclick=on_search_click)
|
||||||
|
))
|
||||||
|
@ -130,7 +130,7 @@ def create_tree(root, populate_data, onclick):
|
|||||||
E.span('\xa0'),
|
E.span('\xa0'),
|
||||||
E.a(
|
E.a(
|
||||||
href='javascript: void(0)',
|
href='javascript: void(0)',
|
||||||
class_='simple-link',
|
class_='simple-link tree-item-title',
|
||||||
onclick=def (event):
|
onclick=def (event):
|
||||||
if onclick:
|
if onclick:
|
||||||
if event.button is 0:
|
if event.button is 0:
|
||||||
@ -138,7 +138,7 @@ def create_tree(root, populate_data, onclick):
|
|||||||
onclick(event, event.currentTarget.parentNode.parentNode)
|
onclick(event, event.currentTarget.parentNode.parentNode)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
E.div(style='display:none'),
|
E.div(style='display:none', data_tree_subtree_container='1'),
|
||||||
data_tree_state='closed',
|
data_tree_state='closed',
|
||||||
)
|
)
|
||||||
ul.appendChild(li)
|
ul.appendChild(li)
|
||||||
@ -153,11 +153,58 @@ def create_tree(root, populate_data, onclick):
|
|||||||
if root:
|
if root:
|
||||||
process_node(root, container, 0)
|
process_node(root, container, 0)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
|
def find_text_in_tree(container, q):
|
||||||
|
q = q.lower()
|
||||||
|
last_match = container.querySelector('a[data-tree-last-match]')
|
||||||
|
if last_match:
|
||||||
|
last_match.parentNode.style.backgroundColor = 'transparent'
|
||||||
|
last_match.parentNode.style.borderRadius = '0'
|
||||||
|
lm = last_match.getAttribute('data-tree-last-match')
|
||||||
|
last_match.removeAttribute('data-tree-last-match')
|
||||||
|
if lm is not q:
|
||||||
|
last_match = None
|
||||||
|
if not q:
|
||||||
|
return
|
||||||
|
before = []
|
||||||
|
seen = False
|
||||||
|
ans = None
|
||||||
|
|
||||||
|
for a in container.querySelectorAll('a.tree-item-title'):
|
||||||
|
if a is last_match:
|
||||||
|
seen = True
|
||||||
|
else:
|
||||||
|
if a.textContent.lower().indexOf(q) != -1:
|
||||||
|
if seen:
|
||||||
|
ans = a
|
||||||
|
break
|
||||||
|
if last_match is None:
|
||||||
|
ans = a
|
||||||
|
break
|
||||||
|
before.push(a)
|
||||||
|
if not ans and before.length:
|
||||||
|
ans = before[0]
|
||||||
|
ans = ans or last_match
|
||||||
|
if ans:
|
||||||
|
ans.dataset.treeLastMatch = q
|
||||||
|
if ans:
|
||||||
|
ans.parentNode.style.backgroundColor = get_color('tree-highlight-item')
|
||||||
|
ans.parentNode.style.borderRadius = '5px'
|
||||||
|
ans = ans.parentNode.parentNode
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def scroll_tree_item_into_view(item):
|
||||||
|
p = item.parentNode?.parentNode
|
||||||
|
while p and p.getAttribute('data-tree-subtree-container'):
|
||||||
|
p.style.display = 'block'
|
||||||
|
p = p.parentNode?.parentNode?.parentNode
|
||||||
|
item.scrollIntoView()
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def get_widget_css():
|
def get_widget_css():
|
||||||
ans = 'a, button:focus { outline: none }; a, button::-moz-focus-inner { border: 0 }\n'
|
ans = 'a, button:focus { outline: none }; a, button::-moz-focus-inner { border: 0 }\n'
|
||||||
ans += '.simple-link { cursor: pointer } .simple-link:hover { color: red } .simple-tree:active { transform: scale(1.5) }\n'
|
ans += '.simple-link { cursor: pointer } .simple-link:hover { color: red } .simple-link:active { transform: scale(1.5) }\n'
|
||||||
ans += create_button.style
|
ans += create_button.style
|
||||||
ans += create_spinner.style
|
ans += create_spinner.style
|
||||||
ans += Breadcrumbs.STYLE_RULES
|
ans += Breadcrumbs.STYLE_RULES
|
||||||
|
Loading…
x
Reference in New Issue
Block a user