Skip to content

Commit

Permalink
Merge 82d34be into 52559a9
Browse files Browse the repository at this point in the history
  • Loading branch information
nvdaes authored Aug 14, 2024
2 parents 52559a9 + 82d34be commit ae331b7
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 7 deletions.
14 changes: 10 additions & 4 deletions nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1000,10 +1000,16 @@ VBufStorage_fieldNode_t* GeckoVBufBackend_t::fillVBuf(
}

BSTR value=NULL;
if(pacc->get_accValue(varChild,&value)==S_OK) {
if(value&&SysStringLen(value)==0) {
SysFreeString(value);
value=NULL;
if (pacc->get_accValue(varChild, &value) == S_OK) {
if (value) {
if (role == ROLE_SYSTEM_LINK) {
// For links, store the IAccessible value to handle same page link detection.
parentNode->addAttribute(L"IAccessible::value", value);
}
if (SysStringLen(value)==0) {
SysFreeString(value);
value=NULL;
}
}
}

Expand Down
32 changes: 32 additions & 0 deletions source/NVDAObjects/IAccessible/ia2Web.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,40 @@ def _get_states(self):
if popupState:
states.discard(controlTypes.State.HASPOPUP)
states.add(popupState)
if self.isInternalLink:
states.add(controlTypes.State.INTERNAL_LINK)
return states

@property
def isInternalLink(self) -> bool:
if self.role != controlTypes.Role.LINK:
return False
value = self.value
if not value:
return False
if not hasattr(self, "treeInterceptor"):
return False
ti = self.treeInterceptor
if ti is None or not hasattr(ti, "documentConstantIdentifier"):
return False
documentConstantIdentifier = ti.documentConstantIdentifier
if self.valueToSamePage(value, documentConstantIdentifier):
return True
return False

def valueToSamePage(self, value: str, constantIdentifier: str) -> bool:
"""Function used to check if link destination points to the same page"""
if not value or not constantIdentifier:
return False
if constantIdentifier.endswith("/"):
constantIdentifier = constantIdentifier[:-1]
queryParamCharPos = constantIdentifier.find("?")
if queryParamCharPos > 0:
constantIdentifier = constantIdentifier[:queryParamCharPos]
if value.startswith(f"{constantIdentifier}#"):
return True
return False

def _get_landmark(self):
xmlRoles = self.IA2Attributes.get("xml-roles", "").split(" ")
landmark = next((xr for xr in xmlRoles if xr in aria.landmarkRoles), None)
Expand Down
4 changes: 4 additions & 0 deletions source/controlTypes/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def negativeDisplayString(self) -> str:
HASPOPUP_GRID = setBit(48)
HASPOPUP_LIST = setBit(49)
HASPOPUP_TREE = setBit(50)
INTERNAL_LINK = setBit(51)


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


Expand Down
9 changes: 6 additions & 3 deletions source/virtualBuffers/gecko_ia2.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,12 @@ def _normalizeControlField(self, attrs): # noqa: C901
attrs["roleTextBraille"] = roleTextBraille
if attrs.get("IAccessible2::attribute_dropeffect", "none") != "none":
states.add(controlTypes.State.DROPTARGET)
if role == controlTypes.Role.LINK and controlTypes.State.LINKED not in states:
# This is a named link destination, not a link which can be activated. The user doesn't care about these.
role = controlTypes.Role.TEXTFRAME
if role == controlTypes.Role.LINK:
if controlTypes.State.LINKED not in states:
# This is a named link destination, not a link which can be activated. The user doesn't care about these.
role = controlTypes.Role.TEXTFRAME
elif self.NVDAObjectAtStart.isInternalLink:
states.add(controlTypes.State.INTERNAL_LINK)
level = attrs.get("IAccessible2::attribute_level", "")
xmlRoles = attrs.get("IAccessible2::attribute_xml-roles", "").split(" ")
landmark = next((xr for xr in xmlRoles if xr in aria.landmarkRoles), None)
Expand Down

0 comments on commit ae331b7

Please sign in to comment.