Merge branch 'force-current-tab' of https://github.com/paretje/qutebrowser into paretje-force-current-tab

This commit is contained in:
Florian Bruhin 2016-04-01 06:13:08 +02:00
commit aad2407de1
8 changed files with 119 additions and 9 deletions

View File

@ -165,6 +165,7 @@ Contributors, sorted by the number of commits in descending order:
* Thorsten Wißmann
* Philipp Hansch
* Austin Anderson
* Kevin Velghe
* Alexey "Averrin" Nabrodov
* avk
* ZDarian
@ -216,7 +217,6 @@ Contributors, sorted by the number of commits in descending order:
* Samuel Loury
* Matthias Lisin
* Marcel Schilling
* Kevin Velghe
* Jean-Christophe Petkovich
* Helen Sherwood-Taylor
* HalosGhost

View File

@ -290,7 +290,8 @@ Start hinting.
* +'target'+: What to do with the selected element.
- `normal`: Open the link in the current tab.
- `normal`: Open the link.
- `current`: Open the link in the current tab.
- `tab`: Open the link in a new tab (honoring the
background-tabs setting).
- `tab-fg`: Open the link in a new foreground tab.

View File

@ -42,10 +42,10 @@ from qutebrowser.misc import guiprocess
ElemTuple = collections.namedtuple('ElemTuple', ['elem', 'label'])
Target = usertypes.enum('Target', ['normal', 'tab', 'tab_fg', 'tab_bg',
'window', 'yank', 'yank_primary', 'run',
'fill', 'hover', 'download', 'userscript',
'spawn'])
Target = usertypes.enum('Target', ['normal', 'current', 'tab', 'tab_fg',
'tab_bg', 'window', 'yank', 'yank_primary',
'run', 'fill', 'hover', 'download',
'userscript', 'spawn'])
class WordHintingError(Exception):
@ -71,7 +71,8 @@ class HintContext:
elems: A mapping from key strings to (elem, label) namedtuples.
baseurl: The URL of the current page.
target: What to do with the opened links.
normal/tab/tab_fg/tab_bg/window: Get passed to BrowserTab.
normal/current/tab/tab_fg/tab_bg/window: Get passed to
BrowserTab.
yank/yank_primary: Yank to clipboard/primary selection.
run: Run a command.
fill: Fill commandline with link.
@ -128,6 +129,7 @@ class HintManager(QObject):
HINT_TEXTS = {
Target.normal: "Follow hint",
Target.current: "Follow hint in current tab",
Target.tab: "Follow hint in new tab",
Target.tab_fg: "Follow hint in foreground tab",
Target.tab_bg: "Follow hint in background tab",
@ -429,6 +431,7 @@ class HintManager(QObject):
"""
target_mapping = {
Target.normal: usertypes.ClickTarget.normal,
Target.current: usertypes.ClickTarget.normal,
Target.tab_fg: usertypes.ClickTarget.tab,
Target.tab_bg: usertypes.ClickTarget.tab_bg,
Target.window: usertypes.ClickTarget.window,
@ -463,6 +466,8 @@ class HintManager(QObject):
QMouseEvent(QEvent.MouseButtonRelease, pos, Qt.LeftButton,
Qt.NoButton, modifiers),
]
if context.target == Target.current:
elem.remove_blank_target()
for evt in events:
self.mouse_event.emit(evt)
if elem.is_text_input() and elem.is_editable():
@ -741,7 +746,8 @@ class HintManager(QObject):
target: What to do with the selected element.
- `normal`: Open the link in the current tab.
- `normal`: Open the link.
- `current`: Open the link in the current tab.
- `tab`: Open the link in a new tab (honoring the
background-tabs setting).
- `tab-fg`: Open the link in a new foreground tab.
@ -891,6 +897,7 @@ class HintManager(QObject):
# Handlers which take a QWebElement
elem_handlers = {
Target.normal: self._click,
Target.current: self._click,
Target.tab: self._click,
Target.tab_fg: self._click,
Target.tab_bg: self._click,

View File

@ -285,6 +285,19 @@ class WebElementWrapper(collections.abc.MutableMapping):
tag = self._elem.tagName().lower()
return self.get('role', None) in roles or tag in ('input', 'textarea')
def remove_blank_target(self):
"""Remove target from link."""
elem = self._elem
for _ in range(5):
if elem is None:
break
tag = elem.tagName().lower()
if tag == 'a' or tag == 'area':
if elem.attribute('target') == '_blank':
elem.setAttribute('target', '_top')
break
elem = elem.parent()
def debug_text(self):
"""Get a text based on an element suitable for debug output."""
self._check_vanished()

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A link to use hints on</title>
</head>
<body>
<a href="/data/hello.txt" target="_blank">Follow me!</a>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A link to use hints on</title>
</head>
<body>
<a href="/data/hello.txt" target="_blank"><span style="font-size: large">Follow me!</span></a>
</body>
</html>

View File

@ -18,3 +18,29 @@ Feature: Using hints
And I run :hint links normal
And I run :follow-hint xyz
Then the error "No hint xyz!" should be shown
Scenario: Following a hint and force to open in current tab.
When I open data/hints/link_blank.html
And I run :hint links current
And I run :follow-hint a
And I wait until data/hello.txt is loaded
Then the following tabs should be open:
- data/hello.txt (active)
Scenario: Following a hint and allow to open in new tab.
When I open data/hints/link_blank.html
And I run :hint links normal
And I run :follow-hint a
And I wait until data/hello.txt is loaded
Then the following tabs should be open:
- data/hints/link_blank.html
- data/hello.txt (active)
Scenario: Following a hint to link with sub-element and force to open in current tab.
When I open data/hints/link_span.html
And I run :tab-close
And I run :hint links current
And I run :follow-hint a
And I wait until data/hello.txt is loaded
Then the following tabs should be open:
- data/hello.txt (active)

View File

@ -36,7 +36,8 @@ from qutebrowser.browser import webelem
def get_webelem(geometry=None, frame=None, null=False, style=None,
display='', attributes=None, tagname=None, classes=None):
display='', attributes=None, tagname=None, classes=None,
parent=None):
"""Factory for WebElementWrapper objects based on a mock.
Args:
@ -55,6 +56,7 @@ def get_webelem(geometry=None, frame=None, null=False, style=None,
elem.tagName.return_value = tagname
elem.toOuterXml.return_value = '<fakeelem/>'
elem.toPlainText.return_value = 'text'
elem.parent.return_value = parent
attribute_dict = {}
if attributes is None:
@ -326,6 +328,47 @@ class TestWebElementWrapper:
assert elem.debug_text() == expected
class TestRemoveBlankTarget:
@pytest.mark.parametrize('tagname', ['a', 'area'])
@pytest.mark.parametrize('target', ['_self', '_parent', '_top', ''])
def test_keep_target(self, tagname, target):
elem = get_webelem(tagname=tagname, attributes={'target': target})
elem.remove_blank_target()
assert elem['target'] == target
@pytest.mark.parametrize('tagname', ['a', 'area'])
def test_no_target(self, tagname):
elem = get_webelem(tagname=tagname)
elem.remove_blank_target()
assert 'target' not in elem
@pytest.mark.parametrize('tagname', ['a', 'area'])
def test_blank_target(self, tagname):
elem = get_webelem(tagname=tagname, attributes={'target': '_blank'})
elem.remove_blank_target()
assert elem['target'] == '_top'
@pytest.mark.parametrize('tagname', ['a', 'area'])
def test_ancestor_blank_target(self, tagname):
elem = get_webelem(tagname=tagname, attributes={'target': '_blank'})
elem_child = get_webelem(tagname='img', parent=elem._elem)
elem_child._elem.encloseWith(elem._elem)
elem_child.remove_blank_target()
assert elem['target'] == '_top'
@pytest.mark.parametrize('depth', [1, 5, 10])
def test_no_link(self, depth):
elem = [None] * depth
elem[0] = get_webelem(tagname='div')
for i in range(1, depth):
elem[i] = get_webelem(tagname='div', parent=elem[i-1])
elem[i]._elem.encloseWith(elem[i-1]._elem)
elem[-1].remove_blank_target()
for i in range(depth):
assert 'target' not in elem[i]
class TestIsVisible:
@pytest.fixture