Hello!
Context
XWIKI-19383: when a link points to a page that does not exist, XWiki renders a “wanted link”. A wanted link is shown with its label, a ? marker, and a href pointing at the creation URL:
<span class="wikicreatelink"><a href="...create..."><span class="wikigeneratedlinkcontent">Label</span></a></span>
Nothing in there says that following the link creates a page rather than opening one. A sighted user has the ? badge in the primary color to highlight this difference. A screen reader user gets a plain link named “Label”, indistinguishable from a working one.
Proposed implementations are in PR xwiki-rendering#256 for the API, and PR xwiki-platform#2104 for their use with translations.
Proposal
Add a component role to xwiki-rendering-api that names the resource a wanted link would create, and have the XHTML link renderer expose what it returns as the text alternative of the link. The role would be org.xwiki.rendering.renderer.reference.link.WantedLinkTitleGenerator:
@Role
@Unstable
public interface WantedLinkTitleGenerator
{
/**
* @param reference the reference of the resource the wanted link points to
* @return the text alternative describing the resource the wanted link would create, as plain text, or
* {@code null} to render the link without one
*/
String generateWantedLinkTitle(ResourceReference reference);
}
- Contract. One method, one argument, and the reference as the only input: an implementation would be a pure naming function, deciding nothing about whether the link is wanted in the first place. The returned string would be plain text, escaped by the renderer, and a
nullreturn would leave the link without a text alternative. - **Lookup.**When the target does not exist
DocumentXHTMLLinkTypeRenderer.beginInternalLinkwould ask the component manager for the implementation registered under a type hint:doc,pageorspace. When there is no implementation for that type, it would fallback on a no-hint default implementation. A lookup that fails would log a warning and fallback similarly. An implementation registered under a hint that is not used would simply never be called. - Reach.
doc,pageandspaceare the only references that can produce a wanted link at all: only links to a page (doc:,page:) or to a space (space:) are checked against the wiki to see whether their target exists. A link to an attachment, a mail address or a URL is rendered by another class. - Default.
DefaultWantedLinkTitleGeneratorwould be registered without a hint and returnCreate resource: <reference>. It would be untranslated on purpose, since the rendering module has no access to the localization. It’s the same patternDefaultPageAttachmentURILabelGeneratorandDataURILabelGeneratoralready follow for labels, the first returning the raw reference and the second a hardcoded EnglishData URI image.
In XS, the text alternatives a user actually gets would then come from implementations registered in xwiki-platform-rendering-xwiki, all using the ContextualLocalizationManager (page/doc, space and a tranlated default specific to xwiki-platform).
Opinion
+1 from me for adding the API as described above, because:
- Nothing in the current markup tells a screen reader user that the link creates a page instead of opening one, and there is no way to add that from the outside: the wanted link is built by the renderer.
- The wording would have to come from outside xwiki-rendering to be translated, and to differ per kind of resource, so a component role seems like the shape that fits. It is also the shape already used right next to it because
computeLabelresolves aURILabelGeneratorusing the type of the link reference. - The complexity would stay limited: one role, one default implementation, and the three implementations on platform.
Conclusion
This new role would become a public API, we need to agree on it so that we can avoid needing to revert it when it’s unstable (or getting stuck with a poor choice after that). There’s at least two things I’d like to settle:
- Naming Are
WantedLinkTitleGeneratorandgenerateWantedLinkTitle(ResourceReference)proper names, and is the reference a correct parameter? - Architecture Does a component role resolved by the type of the reference fit into the architecture, or would another way to do things hold better against time?
Anything else you would want discussed before such a role is validated is welcome to the discussion of course. I’ll close this topic in a week if it doesn’t spur a larger discussion.
Thank you for your interest in the topic! I’m looking forward to your feedback ![]()
Lucas C.
