yes, this looks less complex
This commit is contained in:
parent
aa9e58b520
commit
cb8b16ecc5
@ -141,6 +141,23 @@ class HintManager(QObject):
|
|||||||
|
|
||||||
FIRST_ALPHABETIC = re.compile('[A-Za-z]{3,}')
|
FIRST_ALPHABETIC = re.compile('[A-Za-z]{3,}')
|
||||||
|
|
||||||
|
TAG_EXTRACTORS = dict(
|
||||||
|
alt=lambda elem: elem["alt"],
|
||||||
|
name=lambda elem: elem["name"],
|
||||||
|
title=lambda elem: elem["title"],
|
||||||
|
src=lambda elem: elem["src"].split('/')[-1],
|
||||||
|
href=lambda elem: elem["href"].split('/')[-1],
|
||||||
|
text=lambda elem: str(elem),
|
||||||
|
)
|
||||||
|
|
||||||
|
TAGS_FOR = collections.defaultdict(
|
||||||
|
list, {
|
||||||
|
"IMG": ["alt", "title", "src"],
|
||||||
|
"A": ["title", "href", "text"],
|
||||||
|
"INPUT": ["name"]
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
mouse_event = pyqtSignal('QMouseEvent')
|
mouse_event = pyqtSignal('QMouseEvent')
|
||||||
start_hinting = pyqtSignal(usertypes.ClickTarget)
|
start_hinting = pyqtSignal(usertypes.ClickTarget)
|
||||||
stop_hinting = pyqtSignal()
|
stop_hinting = pyqtSignal()
|
||||||
@ -241,6 +258,36 @@ class HintManager(QObject):
|
|||||||
else:
|
else:
|
||||||
return self._hint_linear(min_chars, chars, elems)
|
return self._hint_linear(min_chars, chars, elems)
|
||||||
|
|
||||||
|
def _extract_tag_words(self, elem):
|
||||||
|
"""Extract tag words form the given element."""
|
||||||
|
yield from (self.TAG_EXTRACTORS[tag](elem)
|
||||||
|
for tag in self.TAGS_FOR[elem.tagName()]
|
||||||
|
if tag in elem or tag == "text")
|
||||||
|
|
||||||
|
def _tag_words_to_hints(self, words):
|
||||||
|
"""Take words and transform them to proper hints if possible."""
|
||||||
|
for candidate in words:
|
||||||
|
if not candidate:
|
||||||
|
continue
|
||||||
|
match = self.FIRST_ALPHABETIC.search(candidate)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
if match.end() - match.start() < 4:
|
||||||
|
continue
|
||||||
|
yield candidate[match.start():match.end()].lower()
|
||||||
|
|
||||||
|
def _any_prefix(self, hint, existing):
|
||||||
|
return any(hint.startswith(e) or e.startswith(hint)
|
||||||
|
for e in existing)
|
||||||
|
|
||||||
|
def _new_hint_for(self, elem, existing):
|
||||||
|
"""Return a hint for elem, not conflicting with the existing."""
|
||||||
|
new = self._tag_words_to_hints(self._extract_tag_words(elem))
|
||||||
|
no_prefixes = (h for h in new if not self._any_prefix(h, existing))
|
||||||
|
# either the first good, or None
|
||||||
|
return next(no_prefixes, None)
|
||||||
|
|
||||||
|
|
||||||
def _hint_words(self, words, elems):
|
def _hint_words(self, words, elems):
|
||||||
"""Produce hint labels based on the html tags.
|
"""Produce hint labels based on the html tags.
|
||||||
|
|
||||||
@ -254,61 +301,10 @@ class HintManager(QObject):
|
|||||||
Return:
|
Return:
|
||||||
A list of hint strings, in the same order as the elements.
|
A list of hint strings, in the same order as the elements.
|
||||||
"""
|
"""
|
||||||
def just_get_it(tag):
|
|
||||||
return lambda elem: elem[tag]
|
|
||||||
|
|
||||||
def take_last_part(tag):
|
|
||||||
return lambda elem: elem[tag].split('/')[-1]
|
|
||||||
|
|
||||||
tag_extractors = dict(alt=just_get_it("alt"),
|
|
||||||
title=just_get_it("title"),
|
|
||||||
src=take_last_part("src"),
|
|
||||||
href=take_last_part("href"),
|
|
||||||
name=just_get_it("name"))
|
|
||||||
|
|
||||||
tags_for = collections.defaultdict(
|
|
||||||
list, {
|
|
||||||
"IMG": ["alt", "title", "src"],
|
|
||||||
"A": ["title", "href"],
|
|
||||||
"INPUT": ["name"]
|
|
||||||
})
|
|
||||||
|
|
||||||
def extract_tag_words(elem):
|
|
||||||
"Extract tag words form the given element."
|
|
||||||
if elem.tagName() == "A":
|
|
||||||
# link text is a special case, alas.
|
|
||||||
yield str(elem)
|
|
||||||
yield from (tag_extractors[tag](elem)
|
|
||||||
for tag in tags_for[elem.tagName()]
|
|
||||||
if tag in elem)
|
|
||||||
|
|
||||||
def tag_words_to_hints(words):
|
|
||||||
"Takes words and transform them to proper hints if possible."
|
|
||||||
for candidate in words:
|
|
||||||
if not candidate:
|
|
||||||
continue
|
|
||||||
match = self.FIRST_ALPHABETIC.search(candidate)
|
|
||||||
if not match:
|
|
||||||
continue
|
|
||||||
if match.end() - match.start() < 4:
|
|
||||||
continue
|
|
||||||
yield candidate[match.start():match.end()].lower()
|
|
||||||
|
|
||||||
def any_prefix(hint, existing):
|
|
||||||
return any(hint.startswith(e) or e.startswith(hint)
|
|
||||||
for e in existing)
|
|
||||||
|
|
||||||
def new_hint_for(elem, existing):
|
|
||||||
"Returns a hint for elem, without conflicting with the existing."
|
|
||||||
new = tag_words_to_hints(extract_tag_words(elem))
|
|
||||||
without_prefixes = (h for h in new if not any_prefix(h, existing))
|
|
||||||
# either the first good, or None
|
|
||||||
return next(without_prefixes, None)
|
|
||||||
|
|
||||||
hints = []
|
hints = []
|
||||||
used_hints = set()
|
used_hints = set()
|
||||||
for elem in elems:
|
for elem in elems:
|
||||||
hint = new_hint_for(elem, used_hints) or next(words)
|
hint = self._new_hint_for(elem, used_hints) or next(words)
|
||||||
used_hints.add(hint)
|
used_hints.add(hint)
|
||||||
hints.append(hint)
|
hints.append(hint)
|
||||||
return hints
|
return hints
|
||||||
|
Loading…
Reference in New Issue
Block a user