Skip to content

Commit

Permalink
Revert "Give ui.browseableMessage the ability to show copy and close …
Browse files Browse the repository at this point in the history
…buttons …"

This reverts commit 2e09be1.
  • Loading branch information
XLTechie authored Aug 13, 2024
1 parent c8a847b commit 19b5cb4
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 190 deletions.
11 changes: 4 additions & 7 deletions source/globalCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,9 @@ def script_reportCurrentSelection(self, gesture):
if scriptCount == 0:
speech.speakTextSelected(info.text)
braille.handler.message(selectMessage)

elif scriptCount == 3:
ui.browseableMessage(info.text, copyButton=True, closeButton=True)
ui.browseableMessage(info.text)
return

elif len(info.text) < speech.speech.MAX_LENGTH_FOR_SELECTION_REPORTING:
Expand Down Expand Up @@ -2209,7 +2210,7 @@ def script_review_currentSymbol(self, gesture):
languageDescription = languageHandler.getLanguageDescription(curLanguage)
# Translators: title for expanded symbol dialog. Example: "Expanded symbol (English)"
title = _("Expanded symbol ({})").format(languageDescription)
ui.browseableMessage(message, title, closeButton=True)
ui.browseableMessage(message, title)

@script(
description=_(
Expand Down Expand Up @@ -2440,8 +2441,6 @@ def _reportFormattingHelper(self, info, browseable=False):
message,
# Translators: title for formatting information dialog.
_("Formatting"),
copyButton=True,
closeButton=True,
)

@staticmethod
Expand Down Expand Up @@ -4141,7 +4140,7 @@ def script_reportLinkDestination(
) -> None:
"""Generates a ui.message or ui.browseableMessage of a link's destination, if focus or caret is
positioned on a link, or an element with an included link such as a graphic.
:param forceBrowseable: skips the press once check, and displays the browseableMessage version.
@param forceBrowseable: skips the press once check, and displays the browseableMessage version.
"""
try:
ti: textInfos.TextInfo = api.getCaretPosition()
Expand Down Expand Up @@ -4175,8 +4174,6 @@ def script_reportLinkDestination(
# Translators: Informs the user that the window contains the destination of the
# link with given title
title=_("Destination of: {name}").format(name=obj.name),
closeButton=True,
copyButton=True,
)
elif presses == 0: # One press
ui.message(linkDestination) # Speak the link
Expand Down
78 changes: 6 additions & 72 deletions source/message.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,90 +4,24 @@
<TITLE></TITLE>
<SCRIPT LANGUAGE=javascript>
<!--
// Though these should be constants, MSHTML does not support const as of 2024
var args = window.dialogArguments;
var copyStatusTimeout = 5000; // milliseconds before copy status message goes away

function handleKeyPress(e) {
function escapeKeyPress(e) {
e = e || window.event;
if(e.keyCode == 27){ // code for escape
window.close();
} else if (e.altKey && e.keyCode == 67) { // code for Alt+C
onCopyButtonPress();
}
}

function onCopyButtonPress() {
// Copy code came from http://www.codestore.net/store.nsf/unid/DOMM-4QHQE8/
var rng = document.body.createTextRange();
rng.moveToElementText(messageDiv);
rng.scrollIntoView();
rng.select();
var success = rng.execCommand("Copy");
rng.collapse(false);
rng.select();
copyStatusDiv.innerHTML = '<p id="copyStatusText" style="font-weight:bold; text-align:center;"></p>';
if (success) { // Notify the user about the copy result
copyStatusText.innerText = args.item('copySuccessfulAlertText');
} else {
copyStatusText.innerText = args.item('copyFailedAlertText');
}
// Time out the user alert message
setTimeout(function() {
copyStatusDiv.innerHTML = '';
}, copyStatusTimeout);
}

function onCloseButtonPress() {
window.close();
}
};

function windowOnLoad() {
var args = window.dialogArguments;
if (args) {
document.title = args.item('title');
// Decide if we are displaying a text only (escaped, sanitized) message, or
// if the caller has sent a raw HTML message that must be interpreted by the browser
if (args.item('messageUsesRawHTML') != null) { // Was set, assume HTML
messageDiv.innerHTML = args.item('message');
} else { // A text only message; the majority of usages
messageDiv.innerHTML = '<pre id="textOnlyMessage"></pre>';
textOnlyMessage.innerText = args.item('message');
}
// If caller wants a close button
if (args.item('closeButtonText') != null) {
closeButton.innerText = args.item('closeButtonText'); // Assign the (translated) label
closeButton.style.display = 'inline'; // Display the button
buttonDiv.style.display = 'block'; // Display the button section
}
// If caller wants a copy to clip button
if (args.item('copyButtonText') != null) {
copyButton.innerText = args.item('copyButtonText'); // Assign the (translated) label
copyButtonSpan.style.display = 'inline'; // Display the button
copyStatusDiv.style.display = 'block'; // Display the copy status
buttonDiv.style.display = 'block'; // Display the section
if (args.item('copyButtonAcceleratorAccessibilityLabel') != null) { // If translated text for the accelerator is provided
copyButtonAcceleratorAccessibilityLabel.innerText = args.item('copyButtonAcceleratorAccessibilityLabel');
}
}
} else { // If args wasn't provided, we can do nothing. Just exit
window.close();
messageID.innerHTML = args.item('message');
}
}
//-->
</SCRIPT>
</HEAD>
<body tabindex='0' id='main_body' style="margin:1em" onload="return windowOnLoad()" onkeydown="return handleKeyPress()" >
<div id="messageDiv"></div>

<!-- "tabindex" is needed to circumvent an old IE/MSHTML bug in the handling of aria-labelledby.
See: https://www.tpgi.com/aria-labelledby-aria-describedby-support-popular-windows-browsers/ -->
<span id="copyButtonAcceleratorAccessibilityLabel" style="visibility: hidden;" tabindex="-1"></span>

<div id="buttonDiv" style="display: none;"><hr>
<div id="copyStatusDiv" role="status" aria-live="polite"></div>
<span id="copyButtonSpan" style="display: none;">
<button id="copyButton" onclick="onCopyButtonPress();" aria-labelledby="copyButton copyButtonAcceleratorAccessibilityLabel"></button>&nbsp;</span>
<span><button id="closeButton" style="display: none;" onclick="onCloseButtonPress();"></button></span>
</div>
<BODY tabindex='0' id='main_body' style="margin:1em" LANGUAGE=javascript onload="return windowOnLoad()" onkeypress="return escapeKeyPress()" >
<div id=messageID></div>
</body>
</html>
135 changes: 26 additions & 109 deletions source/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@
HTMLDLG_VERIFY = 0x0100


def _warnBrowsableMessageNotAvailableOnSecureScreens(title: str | None = None) -> None:
def _warnBrowsableMessageNotAvailableOnSecureScreens(title: Optional[str]) -> None:
"""Warn the user that a browsable message could not be shown on a secure screen (sign-on screen / UAC
prompt).
:param title: If provided, the title of the browsable message to give the user more context.
@param title: If provided, the title of the browsable message to give the user more context.
"""
log.warning(
"While on secure screens browsable messages can not be used."
Expand Down Expand Up @@ -89,67 +88,13 @@ def _warnBrowsableMessageNotAvailableOnSecureScreens(title: str | None = None) -
)


def _warnBrowsableMessageComponentFailure(title: str | None = None) -> None:
"""Warn the user that a browsable message could not be shown because of a component failure.
:param title: If provided, the title of the browsable message to give the user more context.
"""
log.warning(
"A browsable message could not be shown because of a component failure."
f" Attempted to open message with title: {title!r}",
)

if not title:
browsableMessageUnavailableMsg: str = _(
# Translators: This is the message for a warning shown if NVDA cannot open a browsable message window
# because of a component failure.
"An error has caused this feature to be unavailable at this time. "
"Restarting NVDA or Windows may solve this problem.",
)
else:
browsableMessageUnavailableMsg: str = _(
# Translators: This is the message for a warning shown if NVDA cannot open a browsable message window
# because of a component failure. This prompt includes the title
# of the Window that could not be opened for context.
# The {title} will be replaced with the title.
# The title may be something like "Formatting".
"An error has caused this feature ({title}) to be unavailable at this time. "
"Restarting NVDA or Windows may solve this problem.",
)
browsableMessageUnavailableMsg = browsableMessageUnavailableMsg.format(title=title)

import wx # Late import to prevent circular dependency.
import gui # Late import to prevent circular dependency.

log.debug("Presenting browsable message unavailable warning.")
gui.messageBox(
browsableMessageUnavailableMsg,
# Translators: This is the title for a warning dialog, shown if NVDA cannot open a browsable message.
caption=_("Feature unavailable."),
style=wx.ICON_ERROR | wx.OK,
)


def browseableMessage(
message: str,
title: str | None = None,
isHtml: bool = False,
closeButton: bool = False,
copyButton: bool = False,
) -> None:
def browseableMessage(message: str, title: Optional[str] = None, isHtml: bool = False) -> None:
"""Present a message to the user that can be read in browse mode.
The message will be presented in an HTML document.
:param message: The message in either html or text.
:param title: The title for the message, defaults to "NVDA Message".
:param isHtml: Whether the message is html, defaults to False.
:param closeButton: Whether to include a "close" button, defaults to False.
:param copyButton: Whether to include a "copy" (to clipboard) button, defaults to False.
@param message: The message in either html or text.
@param title: The title for the message.
@param isHtml: Whether the message is html
"""
if title is None:
# Translators: The title for the dialog used to present general NVDA messages in browse mode.
title = _("NVDA Message")

if isRunningOnSecureDesktop():
import wx # Late import to prevent circular dependency.

Expand All @@ -158,65 +103,37 @@ def browseableMessage(

htmlFileName = os.path.join(globalVars.appDir, "message.html")
if not os.path.isfile(htmlFileName):
_warnBrowsableMessageComponentFailure(title)
raise LookupError(htmlFileName)

moniker = POINTER(IUnknown)()
try:
windll.urlmon.CreateURLMonikerEx(0, htmlFileName, byref(moniker), URL_MK_UNIFORM)
except Exception as e:
log.error(f"Failed to create URL moniker: {e}")
_warnBrowsableMessageComponentFailure(title)
return

windll.urlmon.CreateURLMonikerEx(0, htmlFileName, byref(moniker), URL_MK_UNIFORM)
if not title:
# Translators: The title for the dialog used to present general NVDA messages in browse mode.
title = _("NVDA Message")
if not isHtml:
message = f"<pre>{escape(message)}</pre>"
try:
d = comtypes.client.CreateObject("Scripting.Dictionary")
except (COMError, OSError):
log.error("Scripting.Dictionary component unavailable", exc_info=True)
_warnBrowsableMessageComponentFailure(title)
# Store the module level message function in a new variable since it is masked by a local variable with
# the same name
messageFunction = globals()["message"]
# Translators: reported when unable to display a browsable message.
messageFunction(_("Unable to display browseable message"))
return
d.add("title", title)

if not isHtml:
message = escape(message)
else:
d.add("messageUsesRawHTML", "true") # Value doesn't matter, as long as there is one
log.warning("Passing raw HTML to ui.browseableMessage!")
d.add("message", message)

# Translators: A notice to the user that a copy operation succeeded.
d.add("copySuccessfulAlertText", _("Text copied."))
# Translators: A notice to the user that a copy operation failed.
d.add("copyFailedAlertText", _("Couldn't copy to clipboard."))
if closeButton:
# Translators: The text of a button which closes the window.
d.add("closeButtonText", _("Close"))
if copyButton:
# Translators: The label of a button to copy the text of the window to the clipboard.
d.add("copyButtonText", _("Copy"))
# Translators: A portion of an accessibility label for the "Copy" button,
# describing the key to press to activate the button. Currently, this key may only be Alt+C.
# Translation makes sense here if the Alt key is called something else in a given language;
# or to set this to the empty string if that key combination is unavailable on some keyboard.
d.add("copyButtonAcceleratorAccessibilityLabel", _("Alt+C"))

dialogArgsVar = automation.VARIANT(d)
gui.mainFrame.prePopup()
try:
windll.mshtml.ShowHTMLDialogEx(
gui.mainFrame.Handle,
moniker,
HTMLDLG_MODELESS,
byref(dialogArgsVar),
DIALOG_OPTIONS,
None,
)
except Exception as e:
log.error(f"Failed to show HTML dialog: {e}")
_warnBrowsableMessageComponentFailure(title)
return
finally:
gui.mainFrame.postPopup()
windll.mshtml.ShowHTMLDialogEx(
gui.mainFrame.Handle,
moniker,
HTMLDLG_MODELESS,
byref(dialogArgsVar),
DIALOG_OPTIONS,
None,
)
gui.mainFrame.postPopup()


def message(
Expand Down
2 changes: 0 additions & 2 deletions user_docs/en/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ The available options are:
### Changes

* The `-c`/`--config-path` and `--disable-addons` command line options are now respected when launching an update from within NVDA. (#16937)
* The Report link destination, Character formatting information, and Speak selection dialogs, now include "Close" and "Copy" buttons for user convenience. (#16369, @XLTechie)
* eSpeak NG has been updated to 1.52-dev commit `961454ff`. (#16775)
* Added new languages Faroese and Xextan.

Expand Down Expand Up @@ -55,7 +54,6 @@ Please refer to [the developer guide](https://www.nvaccess.org/files/nvda/docume
* Please consult the [Custom speech symbol dictionaries section in the developer guide](https://www.nvaccess.org/files/nvda/documentation/developerGuide.html#AddonSymbolDictionaries) for more details.
* It is now possible to redirect objects retrieved from on-screen coordinates, by using the `NVDAObject.objectFromPointRedirect` method. (#16788, @Emil-18)
* Running SCons with the parameter `--all-cores` will automatically pick the maximum number of available CPU cores. (#16943, #16868, @LeonarddeR)
* `ui.browseableMessage` may now be called with options to present a button for copying to clipboard, and/or a button for closing the window. (#16369, @XLTechie)
* Developer info now includes information on app architecture (such as AMD64) for the navigator object. (#16488, @josephsl)

#### Deprecations
Expand Down

0 comments on commit 19b5cb4

Please sign in to comment.