The subjectScheme in DITA is a suitable format for creating a taxonomy of metadata, but how should it really be used? Specifically, my question regards the following:
Can it be used to represent metadata elements, or only metadata attributes? I've only seen it applied to attributes, which makes it kind of limited, since as far as I know elements are usually used for retrieval metada, i.e. not metadata used for filtering.
If you could use it for elements, should the value still be in the "keys" attribute of the subjectdef?
If you want to add a definition/description to a metadata value, where would you do that?
Can/should you publish subjectSchemes? I've seen it suggested that it is not intended for publishing, due to its resource-only default attribute. But isn't that limiting? If you use it to create a taxonomy, surely you would also want a simple way to publish it for the benefit of the users?
I'm going to do my best to address your original questions. Overall, the subjectScheme specialization is designed to create subject classifications and controlled values. It has great functionality for defining subject classifications that can be used for retrieval, as well as defining and controlling attribute values. Currently, the DITA-OT only provides functionality in the area of controlled values for attributes.
Question: "Can it be used to represent metadata elements or only metadata attributes"?
Answer: I would not say that its purpose is to "represent elements or attributes". It is designed to represent subjects and controlled values. Its design is based on keys and so makes heavy use of attributes.
Question: If you want to add a definition for an attribute value, where do you do so?
Answer: You have several options for doing this:
You can create an associated topic that describes the subject or attribute value. You reference this topic using the #href attribute on the subjectdef element. This is especially useful for providing a consensus definition or information about when a conditional-processing value should be used.
You can nest a topicmeta element within the subjectdef element; within the topicmeta element, you have access to the shortdesc and navtitle elements.
You add content to the #navtitle attribute on the subjectdef element. I would not recommend this, as the #navtitle attribute is deprecated and usually cannot be translated.
Question: Can you use the subjectScheme specialization with metadata elements?
Answer: Yes. Off the top of my head, here is one immediate possibility and design for an HTML-based output format:
For a specific subject, add a topicmeta element to the subjectdef element. Within the topicmeta element, you have full access to all the metadata elements. Add as many metadata elements as you like.
Associate the DITA topics with the relevant subject. This can be done either by using specific attribute and values, or by using the subjectref element from the classification domain.
Tweak the output processing so that each DITA topic associated with the subject has the metadata written to the HTML, just as it would be if the metadata elements were located in the DITA topics itself. With this design, you have enforced consistency and, because of the key-based architecture, ease of maintenance and an abstraction layer.
Question: Can you publish subject schemes?
Answer: Yes, if topics are referenced for subjectdef elements using the #href attribute. While by default, the #processing-role attribute for the subjectScheme element is set to "resource-only" and the #toc attribute is set to "no," you can modify those values and they will cascade throughout the map, making it possible to generate output. Of course, this is simply what one can currently do using the DITA-OT; with custom processing implementations, the possibilities are boundless.
I think subjectScheme maps and the classification domain offer lots of exciting possibilities, including faceted and filtered browsing (for output) and faceted searching (for DITA source).
I hope that people building implementations that make use of subjectScheme and classification will share stories, demo their implementations, and so forth. I think that would make what can be done with this part of the DITA architecture clearer and more accessible for people.
As far as the DITA-OT goes, I think you can only use it for conditional processing (filtering and flagging) of elements using DITAVAL files.
I think subject scheme maps have far more potential than this. They could be used for faceted browsing so we could dispense with static topic maps. Static content just seems to belong to the pre-web era. DITA's slightly staid aura could be solved with this.
Anyway, here's what you can currently do:
Subject scheme map:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE subjectScheme PUBLIC "-//OASIS//DTD DITA Subject Scheme Map//EN" "map.dtd">
<subjectScheme>
<hasInstance>
<subjectdef keys="all_routes">
<subjectdef keys="every_route">
<subjectdef keys="anglia"/>
<subjectdef keys="east_midlands"/>
<subjectdef keys="kent"/>
<subjectdef keys="lne_london_north_eastern"/>
<subjectdef keys="lnw_london_north_western"/>
<subjectdef keys="scotland"/>
<subjectdef keys="wales"/>
<subjectdef keys="sussex"/>
<subjectdef keys="wessex"/>
<subjectdef keys="western"/>
</subjectdef>
</subjectdef>
</hasInstance>
<enumerationdef>
<attributedef name="route"/>
<!-- Above is my new specialized attribute "routes"! -->
<subjectdef keyref="all_routes"/>
</enumerationdef>
Here is the topic text with the metadata:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE task PUBLIC "-//OASIS//DTD DITA General Task//EN" "task.dtd">
<task id="task_ozd_ckn_qh">
<title>Route specialization test</title>
<shortdesc route="">This tests the new route attribute!</shortdesc>
<taskbody>
<section>
<title>Lines of text</title>
<p route="anglia">Anglia text text text text text text.</p>
<p route="sussex">Sussex text text text text text text.</p>
<p route="east_midlands">East Midlands text text text text text.</p>
<p route="kent">Kent text text text text text text.</p>
<p route="lne_london_north_eastern"NE text text text text text text.</p>
<p route="lnw_london_north_western">LNW text text text text text text.</p>
<p route="scotland">Scotland text text text text text text.</p>
<p route="sussex"Sussex text text text text text text.</p>
<p route="wales">Wales text text text text text text.</p>
<p route="western">Western text text text text text text.</p>
<p route="wessex">Wessex text text text text text text.</p>
<p route="every_route">Text.</p>
<p>Not profiled.</p>
</section>
</taskbody>
Here's the DITAVAL filter:
<prop action="exclude" att="route"/>
<prop action="include" att="route" val="scotland"/>
This will knock out all the other routes except the route marked with "scotland".
That's basically it.
You can add metadata into the subject scheme map like this:
<subjectdef keys="story_attributedef">
<subjectdef keys="monster">
<hasKind>
<subjectdef keys="zarbi" href="glossary/contemporary.dita">
<topicmeta>
<navtitle>The Zarbi</navtitle>
<shortdesc>Ant-like creature</shortdesc>
</topicmeta>
</subjectdef>
Subject scheme maps are rendered as "resource-only" (whether they have that value or not) so it's not suitable for rendering.
Related
I'm working on a document where, among other things, I need to explain two units that are very similar. I want to reuse text in both descriptions, but I want to use the name of the units in the shared text, and to configure a form of substitution/variable so the name of the units appear in each description. Note that the description of both units appear in the final document.
We're using a structure like this:
top.ditamap, which includes:
units_a_and_b.ditamap, which includes:
unit_a.dita
unit_b.dita
and then this file with text snippets:
unit_a_b_shared.dita
unit_a.dita and unit_b.dita will conref text snippets from unit_a_b_shared.dita.
So basically I want unit_a_b_shared.dita to contain something like this:
"When you configure DOODAA to ..."
and then I want DOODAA to be replaced with unit_a inside the unit_a part of the document, and with unit_b inside the unit_b part.
I've tried to use keywords for this, but so far without success. I haven't found a way to make them take on different values in the different files, even when using keyscopes as explained here:
https://blog.oxygenxml.com/keyscopes/keyscopesBlog.html
The problem seems to be that with keyscopes I need the full path, which includes which unit it is, and hence cannot be used in the text snippet which is shared. Without keyscopes the first definition of the keyword applies everywhere.
Any suggestions on how to achieve this goal (using keywords or not)?
I wrote that key scopes article on the Oxygen XML Blog and I think that key scopes seem to be the answer for your case.
So the "unit_a_b_shared.dita" file would have inside a something like:
<p id="reusablePara">some text before <ph keyref="unit"/> some text after</p>
And then in the DITA Map you would refer to ""unit_a_b_shared.dita"" in different key scopes and re-define the key "unit" in those places to bind it to a different value.
The DITA Map would need to look like this:
<map>
<title>Main</title>
<topicref href="unit_a.dita" keyscope="unitA">
<keydef href="unit_a_b_shared.dita" keys="reusables"/>
<keydef keys="unit">
<topicmeta>
<keywords>
<keyword>KM</keyword>
</keywords>
</topicmeta>
</keydef>
</topicref>
<topicref href="unit_b.dita" keyscope="unitB">
<keydef href="unit_a_b_shared.dita" keys="reusables"/>
<keydef keys="unit">
<topicmeta>
<keywords>
<keyword>KG</keyword>
</keywords>
</topicmeta>
</keydef>
</topicref>
</map>
and inside "unit_a.dita" you would conkeyref to the reusable paragraph inside the "unit_a_b_shared.dita" file:
<p conkeyref="reusables/reusableParagraph"/>
Note that I'm using "conkeyref" not "conref". Once you get to use key scopes you should avoid direct links or direct content references, use only indirect linking using keys.
In Chrome DevTools, the element tab shows the constructed DOM and I can click on elements in the DOM which also highlights the element on the page. Image of both versions shown in DevTools
If the DOM shows:
<input class="gLFyf">
Then the page highlight will show:
input.gLFyF
I realise these are two ways of writing the same thing, I also realise the former is HTML style and the latter follows CSS conventions. However, I lack the vocabulary to properly refer to either.
What do I call each format?
Eg. would it make sense to refer to <input class="gLFyf"> as HTML syntax and input.gLFyF as CSS syntax? Is there a more widely accepted way to differentiate and name them?
gLFyf is the name of the class which is an attribute that can be referred to in the stylesheet to match styles with elements of that class on the page.
A class leads with a period (.) - whereas an ID would lead with a hash (#).
So .gLFyf is a class.
And #gLFyf would be an ID.
It is a class, whether viewing HTML markup or the DOM inspector. They both refer to the same thing as you already state.
This may be of some use/reference.
I have a component using the Rich Text Edit widget (xtype="richtext") in my project that's used across the entire site as the default text component.
The users would like to be able to insert phone links using the tel URI scheme into the text entered using this component.
The dialog allows them to do so but when the contents of the Rich Text Edit are rendered in Sightly/HTL later on, the html context is used:
{$text # context='html'}
Once this is done, the value of my attribute is ignored.
The HTML stored in the repository is:
Call us!
And what's actually rendered on the page on the author instance is:
<a>Call us!</a>
on the publish instance, the tag gets removed altogether because of the link checker.
Changing the context to unsafe causes the href to render but it's not a solution I'm willing to accept. The component is used in a lot of places and I want to be sure the XSS protection is sufficient.
Is there a way I can affect the way the html context in HTL treats telephone links?
I tried adding an extra regular expression to the overlay of apps/cq/xssprotection/config.xml:
<regexp name="onsiteURL" value="([\p{L}\p{N}\\\.\##\$%\+&;\-_~,\?=/!]+|\#(\w)+)"/>
<regexp name="offsiteURL" value="(\s)*((ht|f)tp(s?)://|mailto:)[\p{L}\p{N}]+[\p{L}\p{N}\p{Zs}\.\##\$%\+&;:\-_~,\?=/!]*(\s)*"/>
<regexp name="telephoneLink" value="tel:\+?[0-9]+"/>
and further on:
<attribute name="href">
<regexp-list>
<regexp name="onsiteURL"/>
<regexp name="offsiteURL"/>
<regexp name="telephoneLink"/>
</regexp-list>
<!-- Skipped for brevity -->
</attribute>
but that doesn't seem to affect the way the Sightly/HTL escapes strings in the html context.
I've also tried overlaying the Sling xss rules located in /libs/sling/xss/config.xml but had no luck either.
How can it be done?
There are two xss protection config files:
/libs/cq/xssprotection/config.xml
/libs/sling/xss/config.xml
Sightly is using the second one, which means that you need to overlay it at path /apps/sling/xss/config.xml
What is worth mentioning is that new configuration seems to be applied only after restart of your aem instance.
In the past I have built labels for my form like this:
<label wicket:for="name"><wicket:label><wicket:message key="name"></wicket:message></wicket:label>:</label><input wicket:id="name" type="text"/>
Do I still need to use the wicket:label tag? I am not using wicket:label in wicket 7 and it seems to work fine. I may not be understanding the purpose of using wicket:label. It seems like wicket:label is just additional markup. Below is what I am doing now. Is this correct?:
<label wicket:for="name"><wicket:message key="name"></wicket:message>:</label><input wicket:id="name" type="text"/>
This example is related to Wicket XHTML tags
Have a look at the JavaDoc of AutoLabelResolver and AutoLabelTextResolver.
The <label wicket:for="name"> is handled by AutoLabelResolver. It links the HTML label tag to the HTML form component (in your case the input tag) by filling in the correct ID in the HTML for attribute of the label. It also adds css classes to the label tag for for example errors, so you can style the text in the label tag in case of an error.
The <wicket:label> has two purposes. If you give it a value either by the key attribute (as you did) or by having some text between the tags, the text is set as the label model of the Java FormComponent, which then is used in validation messages like this '${label}' is required. (see LabeledWebMarkupContainer#setLabel and LabeledWebMarkupContainer#getLabel).
If you don't assign any text to the <wicket:label> tag, then it is used as output. That means the value of the label model of your Java FormComponent is used to replace the tag.
If you have no <wicket:label> in the HTML markup and no label model set in your Java code, then your Java FormComponent will have an empty label model and Wicket falls back to using the Wicket ID as label. So depending on how your Wicket IDs look, you will get validator messages like 'user_name' is required. instead of something nice looking like 'User name' is required.
We have a requirement wherein a section of a page will be part authorable and part dynamic. What I mean by this is "You have 6 visits left out of 16." The 6 and 16 in the sentence are coming from a REST service call but the text "You have...visits left out of.." has to be authorable through dialog. Also, we are using AEM 6.
Thanks in advance
Maybe this solution will help others looking for simple placeholder text for their dialog textfields (OP not so much). Use an emptyText attribute...
<dialogText fieldLabel="AEM CLassic UI Text" jcr:primaryType="cq:Widget"
name="./nameOfText" emptyText="THIS IS THE PLACEHOLDER" xtype="textfield"/>
Perhaps you can start by extending foundation/components/text, where the user would be expected to enter a valid formatable string (i.e. "You have %d visits left out of %d").
In your component you would be implementing text.jsp therefore overriding the default behavior of foundation/components/text, in which you can do something like
<cq:text property="text" escapeXml="true"
placeholder="<%= Placeholder.getDefaultPlaceholder(slingRequest, component, null)%>"
tagName="span"
tagClass="myformatedmessage" />
You use tagName and tagClass which will wind up putting the formattable text in a <span class="myformatedmessage">...</span>. Then use jQuery to find it and populate the format placeholders after getting the data via ajax. All that jQuery code you can probably put into a clientlib folder within the same component you extended.
Based on your description, I think you are looking for replacement or substitution instead of placeholders.
"placeholder" generally refers to display text inside a form input that is displayed until the user enters data in the field (such as hint data).
You generally have 3 options for replacing parts of the data:
Server-side (prevents page from being cacheable in dispatcher). Requires parsing authored content & replace some kind of tags with desired REST data, such as "You have ${x} visits left out of ${y} total". Other ways of "tagging" substitution data could look like "You have %x% visits left out of %y%"
client-side JavaScript DOM manipulation once REST data returns. ie $el.html(newDomContentString)
client-side JavaScript templates (handlebars, dust, etc). Takes more initial setup in JS, but generally scales better.