Merge branch 'force-current-tab' of https://github.com/paretje/qutebrowser into paretje-force-current-tab
This commit is contained in:
commit
aad2407de1
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
10
tests/integration/data/hints/link_blank.html
Normal file
10
tests/integration/data/hints/link_blank.html
Normal 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>
|
10
tests/integration/data/hints/link_span.html
Normal file
10
tests/integration/data/hints/link_span.html
Normal 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>
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user