Repository: qutebrowser/qutebrowser

Issue:
JS confirm/prompt doesn't wrap or handle newlines
**Version info (see `:version`)**:
recent
**Does the bug happen if you start with `--temp-basedir`?** (if applicable):
yes
**Description**
If a long string is passed to `window.confirm()` or `window.prompt()` anything that doesn't fit in one line of the prompt box isn't visible. If a multiline string is passed it will all be shown on one line.

On Google Chrome and in qutebrowser with `content.javascript.modal_dialog` set to true newlines are preserved and the message is wrapped to fit the dialog box.

I'm assuming that newlines aren't preserved because the dialog renders text as HTML which treats them as simple whitespace. The not wrapping thing appears to be because the QLabel isn't configured to do so.

This patch should do both of those things but I don't know if there are other ramifications. And I should finish my existing PRs before opening another:
```patch
diff --git i/qutebrowser/browser/shared.py w/qutebrowser/browser/shared.py
index 2398ca2e4d56..c08fc3fd45b0 100644
--- i/qutebrowser/browser/shared.py
+++ w/qutebrowser/browser/shared.py
@@ -82,6 +82,7 @@ def javascript_confirm(url, js_msg, abort_on, *, escape_msg=True):
         raise CallSuper
 
     js_msg = html.escape(js_msg) if escape_msg else js_msg
+    js_msg = js_msg.replace("\n", "<br/>")
     msg = 'From <b>{}</b>:<br/>{}'.format(html.escape(url.toDisplayString()),
                                           js_msg)
     urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
diff --git i/qutebrowser/mainwindow/messageview.py w/qutebrowser/mainwindow/messageview.py
index 43ddd5248444..493fce71095a 100644
--- i/qutebrowser/mainwindow/messageview.py
+++ w/qutebrowser/mainwindow/messageview.py
@@ -35,6 +35,7 @@ class Message(QLabel):
         super().__init__(text, parent)
         self.replace = replace
         self.setAttribute(Qt.WA_StyledBackground, True)
+        self.setWordWrap(True)
         stylesheet = """
             padding-top: 2px;
             padding-bottom: 2px;

```
**How to reproduce**
On a page with javascript enabled open the web inspector console and past in
```javascript
window.confirm(`The best-known Japanese haiku is Bashō's "old pond":

old pond
frog leaps in
water's sound
`)
```
You can try with a [long string](https://en.wikipedia.org/wiki/Lorem_ipsum) yourself.



Discussion:
The patch doesn't works -- new lines in messages are still displayed correctly, but word wrap for long lines doesn't work.

The word wrap must modify in the `mainwindow/prompt.py` file instead:

```diff
--- a/qutebrowser/mainwindow/prompt.py
+++ b/qutebrowser/mainwindow/prompt.py
@@ -521,6 +521,7 @@ class _BasePrompt(QWidget):
         if question.text is not None:
             # Not doing any HTML escaping here as the text can be formatted
             text_label = QLabel(question.text)
+            text_label.setWordWrap(True)
             text_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
             self._vbox.addWidget(text_label)
 
```

Resolving patch:
diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py
--- a/qutebrowser/browser/shared.py
+++ b/qutebrowser/browser/shared.py
@@ -79,6 +79,11 @@ def authentication_required(url, authenticator, abort_on):
     return answer
 
 
+def _format_msg(msg: str) -> str:
+    """Convert message to HTML suitable for rendering."""
+    return html.escape(msg).strip().replace('\n', '<br />')
+
+
 def javascript_confirm(url, js_msg, abort_on):
     """Display a javascript confirm prompt."""
     log.js.debug("confirm: {}".format(js_msg))
@@ -86,7 +91,7 @@ def javascript_confirm(url, js_msg, abort_on):
         raise CallSuper
 
     msg = 'From <b>{}</b>:<br/>{}'.format(html.escape(url.toDisplayString()),
-                                          html.escape(js_msg))
+                                          _format_msg(js_msg))
     urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
     ans = message.ask('Javascript confirm', msg,
                       mode=usertypes.PromptMode.yesno,
@@ -103,7 +108,7 @@ def javascript_prompt(url, js_msg, default, abort_on):
         return (False, "")
 
     msg = '<b>{}</b> asks:<br/>{}'.format(html.escape(url.toDisplayString()),
-                                          html.escape(js_msg))
+                                          _format_msg(js_msg))
     urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
     answer = message.ask('Javascript prompt', msg,
                          mode=usertypes.PromptMode.text,
@@ -126,7 +131,7 @@ def javascript_alert(url, js_msg, abort_on):
         return
 
     msg = 'From <b>{}</b>:<br/>{}'.format(html.escape(url.toDisplayString()),
-                                          html.escape(js_msg))
+                                          _format_msg(js_msg))
     urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
     message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert,
                 abort_on=abort_on, url=urlstr)
diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py
--- a/qutebrowser/mainwindow/prompt.py
+++ b/qutebrowser/mainwindow/prompt.py
@@ -521,6 +521,7 @@ def _init_texts(self, question):
         if question.text is not None:
             # Not doing any HTML escaping here as the text can be formatted
             text_label = QLabel(question.text)
+            text_label.setWordWrap(True)
             text_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
             self._vbox.addWidget(text_label)
 


Test patch: