Implement :insert-text for QtWebEngine

This commit is contained in:
Florian Bruhin 2016-09-07 11:20:32 +02:00
parent ee5a972069
commit 948fa033c7
7 changed files with 47 additions and 24 deletions

View File

@ -1525,32 +1525,28 @@ class CommandDispatcher:
self.insert_text(utils.get_clipboard())
@cmdutils.register(instance='command-dispatcher', maxsplit=0,
scope='window', backend=usertypes.Backend.QtWebKit)
scope='window')
def insert_text(self, text):
"""Insert text at cursor position.
Args:
text: The text to insert.
"""
# FIXME:qtwebengine have a proper API for this
tab = self._current_widget()
if not tab.has_js():
raise cmdexc.CommandError("This command needs javascript enabled.")
page = tab._widget.page() # pylint: disable=protected-access
try:
elem = webkitelem.focus_elem(page.currentFrame())
except webkitelem.IsNullError:
raise cmdexc.CommandError("No element focused!")
if not elem.is_editable(strict=True):
raise cmdexc.CommandError("Focused element is not editable!")
log.misc.debug("Inserting text into element {}".format(
elem.debug_text()))
elem.run_js_async("""
var text = '{}';
var event = document.createEvent('TextEvent');
event.initTextEvent('textInput', true, true, null, text);
this.dispatchEvent(event);
""".format(javascript.string_escape(text)))
def _insert_text_cb(elem):
if elem is None:
message.error(self._win_id, "No element focused!")
return
try:
elem.insert_text(text)
except webelem.Error as e:
message.error(self._win_id, str(e))
return
tab.elements.find_focused(_insert_text_cb)
@cmdutils.register(instance='command-dispatcher', scope='window',
hide=True)

View File

@ -158,6 +158,10 @@ class AbstractWebElement(collections.abc.MutableMapping):
# FIXME:qtwebengine what to do about use_js with WebEngine?
raise NotImplementedError
def insert_text(self, text):
"""Insert the given text into the element."""
raise NotImplementedError
def run_js_async(self, code, callback=None):
"""Run the given JS snippet async on the element."""
# FIXME:qtwebengine get rid of this?

View File

@ -108,6 +108,13 @@ class WebEngineElement(webelem.AbstractWebElement):
js_code = javascript.assemble('webelem', 'set_text', self._id, text)
self._tab.run_js_async(js_code)
def insert_text(self, text):
if not self.is_editable(strict=True):
raise webelem.Error("Element is not editable!")
log.misc.debug("Inserting text into element {!r}".format(self))
js_code = javascript.assemble('webelem', 'insert_text', self._id, text)
self._tab.run_js_async(js_code)
def run_js_async(self, code, callback=None):
"""Run the given JS snippet async on the element."""
# FIXME:qtwebengine get rid of this?

View File

@ -135,6 +135,17 @@ class WebKitElement(webelem.AbstractWebElement):
text = javascript.string_escape(text)
self._elem.evaluateJavaScript("this.value='{}'".format(text))
def insert_text(self, text):
if not self.is_editable(strict=True):
raise webelem.Error("Element is not editable!")
log.misc.debug("Inserting text into element {!r}".format(self))
self.run_js_async("""
var text = '{}';
var event = document.createEvent('TextEvent');
event.initTextEvent('textInput', true, true, null, text);
this.dispatchEvent(event);
""".format(javascript.string_escape(text)))
def run_js_async(self, code, callback=None):
"""Run the given JS snippet async on the element."""
self._check_vanished()

View File

@ -132,6 +132,13 @@ window._qutebrowser.webelem = (function() {
elements[id].value = text;
};
funcs.insert_text = function(id, text) {
var elem = elements[id];
var event = document.createEvent("TextEvent");
event.initTextEvent("textInput", true, true, null, text);
elem.dispatchEvent(event);
};
funcs.element_at_pos = function(x, y) {
// FIXME:qtwebengine
// If the element at the specified point belongs to another document

View File

@ -229,7 +229,6 @@ Feature: Yanking and pasting.
#### :insert-text
@qtwebengine_todo: :insert-text is not implemented yet
Scenario: Inserting text into an empty text field
When I open data/paste_primary.html
And I run :click-element id qute-textarea
@ -238,7 +237,6 @@ Feature: Yanking and pasting.
# Compare
Then the text field should contain "Hello world"
@qtwebengine_todo: :insert-text is not implemented yet
Scenario: Inserting text into a text field at specific position
When I open data/paste_primary.html
And I set the text field to "one two three four"
@ -252,7 +250,6 @@ Feature: Yanking and pasting.
# Compare
Then the text field should contain "onHello worlde two three four"
@qtwebengine_todo: :insert-text is not implemented yet
Scenario: Inserting text into a text field with undo
When I open data/paste_primary.html
And I run :click-element id qute-textarea
@ -265,18 +262,16 @@ Feature: Yanking and pasting.
# Compare
Then the text field should contain "This text should stay"
@qtwebengine_todo: :insert-text is not implemented yet
Scenario: Inserting text without a focused field
When I open data/paste_primary.html
And I run :enter-mode insert
And I run :insert-text test
Then the error "No element focused!" should be shown
@qtwebengine_todo: :insert-text is not implemented yet
Scenario: Inserting text with a read-only field
When I open data/paste_primary.html
And I run :click-element id qute-textarea-noedit
And I wait for "Clicked non-editable element!" in the log
And I run :enter-mode insert
And I run :insert-text test
Then the error "Focused element is not editable!" should be shown
Then the error "Element is not editable!" should be shown

View File

@ -49,8 +49,11 @@ def test_insert_mode(file_name, elem_id, source, input_text, auto_insert,
quteproc.press_keys(input_text)
elif source == 'clipboard':
if request.config.webengine:
pytest.xfail(reason="QtWebEngine TODO: :insert-text is not "
pytest.xfail(reason="QtWebEngine TODO: caret mode is not "
"implemented")
# Note we actually run the keypress tests with QtWebEngine, as for
# some reason it selects all the text when clicking the field the
# second time.
quteproc.send_cmd(':debug-set-fake-clipboard "{}"'.format(input_text))
quteproc.send_cmd(':insert-text {clipboard}')