Skip to content

Commit 895b63f

Browse files
authored
Merge b6227e9 into 4c50375
2 parents 4c50375 + b6227e9 commit 895b63f

4 files changed

Lines changed: 78 additions & 13 deletions

File tree

source/globalCommands.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,8 @@ def script_reportCurrentSelection(self, gesture):
339339
if scriptCount == 0:
340340
speech.speakTextSelected(info.text)
341341
braille.handler.message(selectMessage)
342-
343342
elif scriptCount == 3:
344-
ui.browseableMessage(info.text)
343+
ui.browseableMessage(info.text, copyButton=True, closeButton=True)
345344
return
346345

347346
elif len(info.text) < speech.speech.MAX_LENGTH_FOR_SELECTION_REPORTING:
@@ -2199,7 +2198,7 @@ def script_review_currentSymbol(self, gesture):
21992198
languageDescription = languageHandler.getLanguageDescription(curLanguage)
22002199
# Translators: title for expanded symbol dialog. Example: "Expanded symbol (English)"
22012200
title = _("Expanded symbol ({})").format(languageDescription)
2202-
ui.browseableMessage(message, title)
2201+
ui.browseableMessage(message, title, closeButton=True)
22032202

22042203
@script(
22052204
description=_(
@@ -2430,6 +2429,8 @@ def _reportFormattingHelper(self, info, browseable=False):
24302429
message,
24312430
# Translators: title for formatting information dialog.
24322431
_("Formatting"),
2432+
copyButton=True,
2433+
closeButton=True,
24332434
)
24342435

24352436
@staticmethod
@@ -4113,7 +4114,7 @@ def script_reportLinkDestination(
41134114
) -> None:
41144115
"""Generates a ui.message or ui.browseableMessage of a link's destination, if focus or caret is
41154116
positioned on a link, or an element with an included link such as a graphic.
4116-
@param forceBrowseable: skips the press once check, and displays the browseableMessage version.
4117+
:param forceBrowseable: skips the press once check, and displays the browseableMessage version.
41174118
"""
41184119
try:
41194120
ti: textInfos.TextInfo = api.getCaretPosition()
@@ -4147,6 +4148,8 @@ def script_reportLinkDestination(
41474148
# Translators: Informs the user that the window contains the destination of the
41484149
# link with given title
41494150
title=_("Destination of: {name}").format(name=obj.name),
4151+
closeButton=True,
4152+
copyButton=True,
41504153
)
41514154
elif presses == 0: # One press
41524155
ui.message(linkDestination) # Speak the link

source/message.html

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,66 @@
44
<TITLE></TITLE>
55
<SCRIPT LANGUAGE=javascript>
66
<!--
7-
function escapeKeyPress(e) {
7+
const args = window.dialogArguments;
8+
9+
function handleKeyPress(e) {
810
e = e || window.event;
911
if(e.keyCode == 27){ // code for escape
1012
window.close();
13+
} else if (e.altKey && e.keyCode === 67) { // Code for Alt+c for copy button
14+
onCopyButtonPress();
15+
}
16+
}
17+
18+
function onCopyButtonPress() {
19+
// Copy code came from http://www.codestore.net/store.nsf/unid/DOMM-4QHQE8/
20+
const rng = document.body.createTextRange();
21+
rng.moveToElementText(messageID);
22+
rng.scrollIntoView();
23+
rng.select();
24+
const success = rng.execCommand("Copy");
25+
rng.collapse(false);
26+
rng.select();
27+
if (args) { // Notify the user about the copy result
28+
if (success) {
29+
alert(args.item('copySuccessfulAlertText'));
30+
} else {
31+
alert(args.item('copyFailedAlertText'));
32+
}
1133
}
12-
};
34+
}
35+
36+
function onCloseButtonPress() {
37+
//window.open('', '_self', ''); // Only enable if window.close() stops working in a future version, may fix.
38+
window.close();
39+
}
1340

1441
function windowOnLoad() {
15-
var args = window.dialogArguments;
1642
if (args) {
1743
document.title = args.item('title');
1844
messageID.innerHTML = args.item('message');
45+
// If caller wants a close button
46+
if (args.item('closeButtonText') != null) {
47+
closeButton.innerHTML = args.item('closeButtonText'); // Assign the (translated) label
48+
closeButton.style.display = 'inline'; // Display the button
49+
buttonDiv.style.display = 'block'; // Display the div
50+
}
51+
// If caller wants a copy to clip button
52+
if (args.item('copyButtonText') != null) {
53+
copyButton.innerHTML = args.item('copyButtonText'); // Assign the (translated) label
54+
copyButtonSpan.style.display = 'inline'; // Display the button
55+
buttonDiv.style.display = 'block'; // Display the div
56+
}
1957
}
2058
}
2159
//-->
2260
</SCRIPT>
2361
</HEAD>
24-
<BODY tabindex='0' id='main_body' style="margin:1em" LANGUAGE=javascript onload="return windowOnLoad()" onkeypress="return escapeKeyPress()" >
62+
<body tabindex='0' id='main_body' style="margin:1em" LANGUAGE=javascript onload="return windowOnLoad()" onkeypress="return handleKeyPress()" >
2563
<div id=messageID></div>
64+
<div id="buttonDiv" style="display: none;"><hr>
65+
<span id="copyButtonSpan" style="display: none;"><button id="copyButton" onclick="onCopyButtonPress();"></button>&nbsp;</span>
66+
<span><button id="closeButton" style="display: none;" onclick="onCloseButtonPress();"></button></span>
67+
</div>
2668
</body>
2769
</html>

source/ui.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,20 @@ def _warnBrowsableMessageNotAvailableOnSecureScreens(title: Optional[str]) -> No
8888
)
8989

9090

91-
def browseableMessage(message: str, title: Optional[str] = None, isHtml: bool = False) -> None:
91+
def browseableMessage(
92+
message: str,
93+
title: str | None = None,
94+
isHtml: bool = False,
95+
closeButton: bool = False,
96+
copyButton: bool = False
97+
) -> None:
9298
"""Present a message to the user that can be read in browse mode.
9399
The message will be presented in an HTML document.
94-
@param message: The message in either html or text.
95-
@param title: The title for the message.
96-
@param isHtml: Whether the message is html
100+
:param message: The message in either html or text.
101+
:param title: The title for the message, defaults to "NVDA Message".
102+
:param isHtml: Whether the message is html, defaults to False.
103+
:param closeButton: Whether to include a "close" button, defaults to False.
104+
:param copyButton: Whether to include a "copy" (to clipboard) button, defaults to False.
97105
"""
98106
if isRunningOnSecureDesktop():
99107
import wx # Late import to prevent circular dependency.
@@ -106,7 +114,7 @@ def browseableMessage(message: str, title: Optional[str] = None, isHtml: bool =
106114
raise LookupError(htmlFileName)
107115
moniker = POINTER(IUnknown)()
108116
windll.urlmon.CreateURLMonikerEx(0, htmlFileName, byref(moniker), URL_MK_UNIFORM)
109-
if not title:
117+
if title is None:
110118
# Translators: The title for the dialog used to present general NVDA messages in browse mode.
111119
title = _("NVDA Message")
112120
if not isHtml:
@@ -123,6 +131,16 @@ def browseableMessage(message: str, title: Optional[str] = None, isHtml: bool =
123131
return
124132
d.add("title", title)
125133
d.add("message", message)
134+
# Translators: A notice to the user that the copy operation succeeded.
135+
d.add("copySuccessfulAlertText", _("Text copied."))
136+
# Translators: Notice to the user that the copy operation failed.
137+
d.add("copyFailedAlertText", _("Couldn't copy to clipboard."))
138+
if closeButton:
139+
# Translators: The text of a button which closes the window.
140+
d.add("closeButtonText", _("Close"))
141+
if copyButton:
142+
# Translators: The text of a button to copy the text of the window to the clipboard.
143+
d.add("copyButtonText", _("Copy"))
126144
dialogArgsVar = automation.VARIANT(d)
127145
gui.mainFrame.prePopup()
128146
windll.mshtml.ShowHTMLDialogEx(

user_docs/en/changes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Unicode CLDR has also been updated.
7070
* When reading by line in browse mode, "caption" is no longer reported on each line of a long figure or table caption. (#14874)
7171
* In the Python console, the last unexecuted command will no longer be lost when moving in the input history. (#16653, @CyrilleB79)
7272
* A unique anonymous ID is now sent as part of optional NVDA usage statistics gathering. (#16266)
73+
* The Report link destination, Character formatting information, and Speak selection dialogs, now include "Close" and "Copy" buttons for user convenience. (#16369, @XLTechie)
7374
* By default, a new folder will be created when making a portable copy.
7475
A warning message will inform you if you try writing to a non-empty directory. (#16684)
7576

@@ -116,6 +117,7 @@ It is especially useful to read the error location markers in tracebacks. (#1632
116117
Jobs are scheduled with a delay to avoid conflicts.
117118
* `scheduleThread.scheduleDailyJob` and `scheduleJob` can be used to schedule jobs at custom times, where a `JobClashError` will be raised on a known job scheduling clash.
118119
* It is now possible to create app modules for apps hosting Edge WebView2 (msedgewebview2.exe) controls. (#16705, @josephsl)
120+
* `ui.browseableMessage` may now be called with options to present a button for copying to clipboard, and a button for closing the window. (#16369, @XLTechie)
119121

120122
## 2024.2
121123

0 commit comments

Comments
 (0)