Skip to content

Commit 4516d2d

Browse files
authored
Merge eb01b6f into 52559a9
2 parents 52559a9 + eb01b6f commit 4516d2d

6 files changed

Lines changed: 79 additions & 7 deletions

File tree

nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,10 +1000,16 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
10001000
}
10011001

10021002
BSTR value=NULL;
1003-
if(pacc->get_accValue(varChild,&value)==S_OK) {
1004-
if(value&&SysStringLen(value)==0) {
1005-
SysFreeString(value);
1006-
value=NULL;
1003+
if (pacc->get_accValue(varChild, &value) == S_OK) {
1004+
if (value) {
1005+
if (role == ROLE_SYSTEM_LINK) {
1006+
// For links, store the IAccessible value to handle same page link detection.
1007+
parentNode->addAttribute(L"IAccessible::value", value);
1008+
}
1009+
if (SysStringLen(value)==0) {
1010+
SysFreeString(value);
1011+
value=NULL;
1012+
}
10071013
}
10081014
}
10091015

source/NVDAObjects/IAccessible/ia2Web.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,40 @@ def _get_states(self):
213213
if popupState:
214214
states.discard(controlTypes.State.HASPOPUP)
215215
states.add(popupState)
216+
if config.conf["documentFormatting"]["reportLinkType"] and self.isInternalLink:
217+
states.add(controlTypes.State.INTERNAL_LINK)
216218
return states
217219

220+
@property
221+
def isInternalLink(self) -> bool:
222+
if self.role != controlTypes.Role.LINK:
223+
return False
224+
value = self.value
225+
if not value:
226+
return False
227+
if not hasattr(self, "treeInterceptor"):
228+
return False
229+
ti = self.treeInterceptor
230+
if ti is None or not hasattr(ti, "documentConstantIdentifier"):
231+
return False
232+
documentConstantIdentifier = ti.documentConstantIdentifier
233+
if self._valueToSamePage(value, documentConstantIdentifier):
234+
return True
235+
return False
236+
237+
def _valueToSamePage(self, value: str, constantIdentifier: str) -> bool:
238+
"""Function used to check if link destination points to the same page"""
239+
if not value or not constantIdentifier:
240+
return False
241+
if constantIdentifier.endswith("/"):
242+
constantIdentifier = constantIdentifier[:-1]
243+
queryParamCharPos = constantIdentifier.find("?")
244+
if queryParamCharPos > 0:
245+
constantIdentifier = constantIdentifier[:queryParamCharPos]
246+
if value.startswith(f"{constantIdentifier}#"):
247+
return True
248+
return False
249+
218250
def _get_landmark(self):
219251
xmlRoles = self.IA2Attributes.get("xml-roles", "").split(" ")
220252
landmark = next((xr for xr in xmlRoles if xr in aria.landmarkRoles), None)

source/config/configSpec.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@
239239
# 0: Off, 1: style, 2: color and style
240240
reportCellBorders = integer(0, 2, default=0)
241241
reportLinks = boolean(default=true)
242+
reportLinkType = featureFlag(optionsEnum="BoolFlag", behaviorOfDefault="disabled")
242243
reportGraphics = boolean(default=True)
243244
reportComments = boolean(default=true)
244245
reportBookmarks = boolean(default=true)

source/controlTypes/state.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def negativeDisplayString(self) -> str:
102102
HASPOPUP_GRID = setBit(48)
103103
HASPOPUP_LIST = setBit(49)
104104
HASPOPUP_TREE = setBit(50)
105+
INTERNAL_LINK = setBit(51)
105106

106107

107108
STATES_SORTED = frozenset([State.SORTED, State.SORTED_ASCENDING, State.SORTED_DESCENDING])
@@ -204,6 +205,9 @@ def negativeDisplayString(self) -> str:
204205
State.HASPOPUP_LIST: _("opens list"),
205206
# Translators: Presented when a control has a pop-up tree.
206207
State.HASPOPUP_TREE: _("opens tree"),
208+
# Translators: Presented when a link destination points to the page containing the link.
209+
# For example, links of a table of contents of a document with different sections.
210+
State.INTERNAL_LINK: _("same page"),
207211
}
208212

209213

source/globalCommands.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,31 @@ def script_toggleReportLinks(self, gesture):
902902
config.conf["documentFormatting"]["reportLinks"] = True
903903
ui.message(state)
904904

905+
@script(
906+
# Translators: Input help mode message for cycle through report link type command.
907+
description=_("Cycles through the report link type states"),
908+
category=SCRCAT_DOCUMENTFORMATTING,
909+
)
910+
def script_cyclesReportLinkType(self, gesture: inputCore.InputGesture) -> None:
911+
"""Set next state of report link type and reports it with ui.message."""
912+
featureFlag: FeatureFlag = config.conf["documentFormatting"]["reportLinkType"]
913+
boolFlag: BoolFlag = featureFlag.enumClassType
914+
values = [x.value for x in boolFlag]
915+
currentValue = featureFlag.value.value
916+
nextValueIndex = (currentValue % len(values)) + 1
917+
nextName: str = boolFlag(nextValueIndex).name
918+
config.conf["documentFormatting"]["reportLinkType"] = nextName
919+
featureFlag = config.conf["documentFormatting"]["reportLinkType"]
920+
if featureFlag.isDefault():
921+
# Translators: Used to announce reporting link type state
922+
# (default behavior).
923+
msg = _("Report link type default (%s)") % featureFlag.behaviorOfDefault.displayString
924+
else:
925+
# Translators: Announces which report link type state is used
926+
# (disabled or enabled).
927+
msg = _("Report link type %s") % BoolFlag[nextName].displayString
928+
ui.message(msg)
929+
905930
@script(
906931
# Translators: Input help mode message for toggle report graphics command.
907932
description=_("Toggles on and off the reporting of graphics"),

source/virtualBuffers/gecko_ia2.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,13 @@ def _normalizeControlField(self, attrs): # noqa: C901
167167
attrs["roleTextBraille"] = roleTextBraille
168168
if attrs.get("IAccessible2::attribute_dropeffect", "none") != "none":
169169
states.add(controlTypes.State.DROPTARGET)
170-
if role == controlTypes.Role.LINK and controlTypes.State.LINKED not in states:
171-
# This is a named link destination, not a link which can be activated. The user doesn't care about these.
172-
role = controlTypes.Role.TEXTFRAME
170+
if role == controlTypes.Role.LINK:
171+
if controlTypes.State.LINKED not in states:
172+
# This is a named link destination, not a link which can be activated. The user doesn't care about these.
173+
role = controlTypes.Role.TEXTFRAME
174+
elif self.NVDAObjectAtStart.isInternalLink:
175+
if config.conf["documentFormatting"]["reportLinkType"]:
176+
states.add(controlTypes.State.INTERNAL_LINK)
173177
level = attrs.get("IAccessible2::attribute_level", "")
174178
xmlRoles = attrs.get("IAccessible2::attribute_xml-roles", "").split(" ")
175179
landmark = next((xr for xr in xmlRoles if xr in aria.landmarkRoles), None)

0 commit comments

Comments
 (0)