Skip to content

Commit ff71fb1

Browse files
authored
Merge 1cb3e84 into e57d7e5
2 parents e57d7e5 + 1cb3e84 commit ff71fb1

4 files changed

Lines changed: 65 additions & 14 deletions

File tree

source/globalCommands.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,8 @@ def script_reportCurrentSelection(self,gesture):
335335
if scriptCount == 0:
336336
speech.speakTextSelected(info.text)
337337
braille.handler.message(selectMessage)
338-
339338
elif scriptCount == 3:
340-
ui.browseableMessage(info.text)
339+
ui.browseableMessage(info.text, copyButton=True, closeButton=True)
341340
return
342341

343342
elif len(info.text) < speech.speech.MAX_LENGTH_FOR_SELECTION_REPORTING:
@@ -2160,7 +2159,7 @@ def script_review_currentSymbol(self,gesture):
21602159
languageDescription = languageHandler.getLanguageDescription(curLanguage)
21612160
# Translators: title for expanded symbol dialog. Example: "Expanded symbol (English)"
21622161
title = _("Expanded symbol ({})").format(languageDescription)
2163-
ui.browseableMessage(message, title)
2162+
ui.browseableMessage(message, title, closeButton=True)
21642163

21652164
@script(
21662165
description=_(
@@ -2391,7 +2390,8 @@ def _reportFormattingHelper(self, info, browseable=False):
23912390
ui.browseableMessage(
23922391
message,
23932392
# Translators: title for formatting information dialog.
2394-
_("Formatting")
2393+
_("Formatting"),
2394+
copyButton=True, closeButton=True
23952395
)
23962396

23972397
@staticmethod
@@ -4052,7 +4052,7 @@ def script_reportLinkDestination(
40524052
) -> None:
40534053
"""Generates a ui.message or ui.browseableMessage of a link's destination, if focus or caret is
40544054
positioned on a link, or an element with an included link such as a graphic.
4055-
@param forceBrowseable: skips the press once check, and displays the browseableMessage version.
4055+
:param forceBrowseable: skips the press once check, and displays the browseableMessage version.
40564056
"""
40574057
try:
40584058
ti: textInfos.TextInfo = api.getCaretPosition()
@@ -4089,7 +4089,8 @@ def script_reportLinkDestination(
40894089
linkDestination,
40904090
# Translators: Informs the user that the window contains the destination of the
40914091
# link with given title
4092-
title=_("Destination of: {name}").format(name=obj.name)
4092+
title=_("Destination of: {name}").format(name=obj.name),
4093+
closeButton=True, copyButton=True
40934094
)
40944095
elif presses == 0: # One press
40954096
ui.message(linkDestination) # Speak the link

source/message.html

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,58 @@
44
<TITLE></TITLE>
55
<SCRIPT LANGUAGE=javascript>
66
<!--
7-
function escapeKeyPress(e) {
7+
function handleKeyPress(e) {
88
e = e || window.event;
99
if(e.keyCode == 27){ // code for escape
1010
window.close();
11+
} else if (e.altKey && e.keyCode === 67) {
12+
onCopyButtonPress();
1113
}
12-
};
14+
}
15+
16+
function onCopyButtonPress() {
17+
// Copy code came from http://www.codestore.net/store.nsf/unid/DOMM-4QHQE8/
18+
var rng = document.body.createTextRange();
19+
rng.moveToElementText(messageID);
20+
rng.scrollIntoView();
21+
rng.select();
22+
rng.execCommand("Copy");
23+
rng.collapse(false);
24+
rng.select();
25+
}
26+
27+
function onCloseButtonPress() {
28+
//window.open('', '_self', ''); // Only enable if window.close() stops working in a future version, may fix.
29+
window.close();
30+
}
1331

1432
function windowOnLoad() {
1533
var args = window.dialogArguments;
1634
if (args) {
1735
document.title = args.item('title');
1836
messageID.innerHTML = args.item('message');
37+
// If caller wants a close button
38+
if (args.item('closeButtonText') != null) {
39+
closeButton.innerHTML = args.item('closeButtonText'); // Assign the (translated) label
40+
closeButton.style.display = 'inline'; // Display the button
41+
buttonDiv.style.display = 'block'; // Display the div
42+
}
43+
// If caller wants a copy to clip button
44+
if (args.item('copyButtonText') != null) {
45+
copyButton.innerHTML = args.item('copyButtonText'); // Assign the (translated) label
46+
copyButtonSpan.style.display = 'inline'; // Display the button
47+
buttonDiv.style.display = 'block'; // Display the div
48+
}
1949
}
2050
}
2151
//-->
2252
</SCRIPT>
2353
</HEAD>
24-
<BODY tabindex='0' id='main_body' style="margin:1em" LANGUAGE=javascript onload="return windowOnLoad()" onkeypress="return escapeKeyPress()" >
54+
<BODY tabindex='0' id='main_body' style="margin:1em" LANGUAGE=javascript onload="return windowOnLoad()" onkeypress="return handleKeyPress()" >
2555
<div id=messageID></div>
56+
<div id="buttonDiv" style="display: none;"><hr>
57+
<span id="copyButtonSpan" style="display: none;"><button id="copyButton" onclick="onCopyButtonPress();"></button>&nbsp;</span>
58+
<span><button id="closeButton" style="display: none;" onclick="onCloseButtonPress();"></button></span>
59+
</div>
2660
</body>
2761
</html>

source/ui.py

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

9191

92-
def browseableMessage(message: str, title: Optional[str] = None, isHtml: bool = False) -> None:
92+
def browseableMessage(
93+
message: str,
94+
title: Optional[str] = None,
95+
isHtml: bool = False,
96+
closeButton: bool = False,
97+
copyButton: bool = False
98+
) -> None:
9399
"""Present a message to the user that can be read in browse mode.
94100
The message will be presented in an HTML document.
95-
@param message: The message in either html or text.
96-
@param title: The title for the message.
97-
@param isHtml: Whether the message is html
101+
:param message: The message in either html or text.
102+
:param title: The title for the message, defaults to "NVDA Message".
103+
:param isHtml: Whether the message is html, defaults to False.
104+
:param closeButton: Whether to include a "close" button, defaults to False.
105+
:param copyButton: Whether to include a "copy" (to clipboard) button, defaults to False.
98106
"""
99107
if isRunningOnSecureDesktop():
100108
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,12 @@ def browseableMessage(message: str, title: Optional[str] = None, isHtml: bool =
123131
return
124132
d.add("title", title)
125133
d.add("message", message)
134+
if closeButton:
135+
# Translators: The text of a button which closes the window.
136+
d.add("closeButtonText", _("Close"))
137+
if copyButton:
138+
# Translators: The text of a button to copy the text of the window to the clipboard.
139+
d.add("copyButtonText", _("Copy"))
126140
dialogArgsVar = automation.VARIANT(d)
127141
gui.mainFrame.prePopup()
128142
windll.mshtml.ShowHTMLDialogEx(

user_docs/en/changes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Unicode CLDR has also been updated.
4646
* In the Python console, the last unexecuted command will no longer be lost when moving in the input history. (#16653, @CyrilleB79)
4747
* A unique anonymous ID is now sent as part of optional NVDA usage statistics gathering. (#16266)
4848
* By default, a new folder will be created when making a portable copy. Warnings have been added when writing to a non-empty directory. (#16684)
49+
* The Report link destination and character formatting information windows, now include "Close" and "Copy" buttons for user convenience. (#16369, @XLTechie)
4950

5051
### Bug Fixes
5152
* Windows 11 fixes:
@@ -85,6 +86,7 @@ It is especially useful to read the error location markers in tracebacks. (#1632
8586
Jobs are scheduled with a delay to avoid conflicts.
8687
* `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.
8788
* It is now possible to create app modules for apps hosting Edge WebView2 (msedgewebview2.exe) controls. (#16705, @josephsl)
89+
* `ui.browseableMessage` may now be called with options to present a button for copying to clipboard, and also an optional close button which may have its name customized. (#16369, @XLTechie)
8890

8991
#### Deprecations
9092

0 commit comments

Comments
 (0)