Search results

DITA: Create a content filter to dynamically filter content

You can include a content selector that allows users to toggle content on or off. This is useful if, for example, you have some content you want to show or hide from users, such as code snippets for a particular programming language.

For example, suppose your content has four programming language code snippets. You want to allow your users to select one language and have all the rest be hidden. You can add a content selector to your output so that users can select the type of content they want to see.

This content selector is a style switcher developed by hibbard.eu explained here: Using cookies with jQuery to make a simple style switcher. Although there are a variety of jQuery style switchers available, I like this one because it implements the jQuery cookie to remember the user's selection from page to page. This is critical for the content selector to work site-wide. (Without the cookie, the user would need to re-select an option with each new page.

To implement the content selector:

  1. In a text editor, open the web_topic.js file found in the following directory: [Oxygen Install Directory]/frameworks/dita/DITA-OT/plugins/com.oxygenxml.webhelp/oxygen-webhelp/resources/js
  2. Before the closing )};, add the following script:
       function removeAddBodyClass(){
        <em class="hl-comment" style="color:#006400">/* For topics loaded in iFrame */</em>
        $(<span class="hl-string" style="color:#2a00ff">"body"</span>).removeClass();
        $(<span class="hl-string" style="color:#2a00ff">"body"</span>).addClass($.cookie(<span class="hl-string" style="color:#2a00ff">'body_colour'</span>));
        <em class="hl-comment" style="color:#006400">/* For TOC */</em>
        $(<span class="hl-string" style="color:#2a00ff">"#bck_toc"</span>, parent.document).removeClass();
        $(<span class="hl-string" style="color:#2a00ff">"#bck_toc"</span>, parent.document).addClass($.cookie(<span class="hl-string" style="color:#2a00ff">'body_colour'</span>));
    }
    
        removeAddBodyClass();
    
        $(<span class="hl-string" style="color:#2a00ff">"#selector"</span>).change(function(){
        $.cookie(<span class="hl-string" style="color:#2a00ff">'body_colour'</span>, $(<span class="hl-string" style="color:#2a00ff">"#selector"</span>).val());
        removeAddBodyClass();
        });
    
        $(<span class="hl-string" style="color:#2a00ff">"#selector > option"</span>).each(function() {
        if($(this).val() == $.cookie(<span class="hl-string" style="color:#2a00ff">'body_colour'</span>)){
        $(this).attr(<span class="hl-string" style="color:#2a00ff">"selected"</span>,<span class="hl-string" style="color:#2a00ff">"selected"</span>);
        }
        });
        

    This script is from the demo download zip file available on Hibbard's site. (Scroll to the bottom of the page where you can download the demo as a zip file; then open one of the HTML files to see the script.) There is one modification, though. I added the #bck_toc", parent.document triggers to apply the same adding and removing of classes to the table of contents. This is because OxygenXML's output puts the TOC and the body in separate frames.

  3. Save the file.
  4. By default, attributes you add to content, such as platform="java" won't appear in the output (they're stripped out entirely). We need to hack Oxygen's webhelp XSLT to allow these tags to pass through. In a text editor, open the dita2htmllmpl.xsl file found in the following directory: [Oxygen Install Directory]/frameworks/dita/DITA-OT/plugins/org.dita.xhtml/xsl/xslhtml.
  5. Locate the line that begins "" and replace that section with the following:
      <xsl:template name="commonattributes">
        <xsl:param name="default-output-class"/>
        <xsl:apply-templates select="@xml:lang"/>
        <xsl:apply-templates select="@dir"/>
        <xsl:apply-templates select="*[contains(@class, '
          ditaot-d/ditaval-startprop ')]/@outputclass" mode="add-ditaval-style"/>
        <xsl:apply-templates select="." mode="set-output-class">
          <xsl:with-param name="default" select="$default-output-class"/>
        </xsl:apply-templates>
        <xsl:if test="@audience">
          <xsl:attribute name="data-audience"><xsl:value-of
            select="@audience"/></xsl:attribute>
        </xsl:if>
        <xsl:if test="@platform">
          <xsl:attribute name="data-platform"><xsl:value-of
            select="@platform"/></xsl:attribute>
        </xsl:if>
        <xsl:if test="@id">
          <xsl:attribute name="id"><xsl:value-of
            select="@id"/></xsl:attribute>
        </xsl:if>
      </xsl:template>
         

    This will allow the platform, audience, and id attributes to pass through as attributes in the output (so you can leverage them). Without these attributes in the output, you won't be able to select the content.

    Note that in the future, this hack may be unnecessary. The ditaval file allows you to add a passthrough attribute to elements, but this attribute does not work in Oxygen's webhelp output.

  6. Go to your custom skin's stylesheet. Near the bottom, add the following styles:
         <em class="hl-comment" style="color:#006400">/* by default, java is shown because on initial page load, we don't want blank spaces with no code.*/</em>
    #bck_toc li.cpp, #bck_toc li.dotnet, #bck_toc li.php, body [data-platform*=cpp], body [data-platform*=dotnet], body [data-platform*=php] {
        display: none;
    }
    body.java [data-platform*=java] {
        display: block!important;
    }
    body.java .ph[data-platform*=java] {
        display: inline!important;
    }
    #bck_toc.java li.java, body.cpp [data-platform*=cpp] {
        display: block!important;
    }
    body.cpp .ph[data-platform*=cpp] {
        display: inline!important;
    }
    #bck_toc.cpp li.cpp {
        display: block!important;
    }
    #bck_toc.cpp li.java, body.cpp [data-platform*=java] {
        display: none;
    }
    body.dotnet [data-platform*=dotnet] {
        display: block!important;
    }
    body.dotnet .ph[data-platform*=dotnet] {
        display: inline!important;
    }
    #bck_toc.dotnet li.dotnet {
        display: block!important;
    }
    #bck_toc.dotnet li.java, body.dotnet [data-platform*=java] {
        display: none;
    }
    body.php [data-platform*=php] {
        display: block!important;
    }
    body.php .ph[data-platform*=php] {
        display: inline!important;
    }
    #bck_toc.php li.php {
        display: block!important;
    }
    #bck_toc.php li.java, body.php [data-platform*=java] {
        display: none;
    }
    
    
        #progSelector {
        margin-left:<span class="hl-number">600</span>px;
    
        }
        

    You will need to adjust this code depending on the classes you're adding. For example, if you don't want your four selections to be java, php, dotnet, and cpp, swap in the classes you intend to use. Also, if you're not using platform but rather product or audience, make that switch as well.

    Basically, here's a summary of what's going on with this CSS. By default, the content selector doesn't have an initial selection. In this example, anything tagged with the class cpp, dotnet, or php will initially be hidden, but not java. This is because we don't want blank spaces in the code to appear before the user selects something in the content selector. (By the way, make sure that the default content that appears (e.g., java) is first in your selector's options. This step is described later).

    When a user makes a selection from the selector, the jQuery script adds a class to the body element. The selector body.cpp [data-platform*="cpp"] says for anything inside the bodyelement with the cpp class that also has the attribute of data-platform=cpp, then apply this style.

    When a user makes a selection, we want to display content with that data attribute, so we set display:block. We also hide the java (which was never hidden by default). For any non-block level items, we want to set their display as display:inline rather than block so that we don't end up with paragraph breaks for inline elements. Right now only ph elements are set as display:inline, but if there are others, add them there following the same pattern. (Unfortunately, in the world of CSS, there is no opposite to display:none -- only display:block or display:inline.

    The .ph[data-platform*="java"] selector means that for any ph classes that contain an attribute of data-platform, apply this style.

  7. Add a selector in your header file to allow users to select the content they want to see. To do this, create a new XHTML file and add the following:
    <p id="progSelector">Select your programming language: <select id="selector">
        <option value="java">Java</option>
        <option value="dotnet">.NET</option>
        <option value="cpp">C++</option>
        <option value="php">PHP</option>
    </select></p>
       

    Replace the options with whatever you want. Just keep in mind that the values must match your classes. Also, by default, the first option will appear in the selector, even though the user hasn't actually made that selection. This is why java is not hidden by default in the styles.

  8. In OxygenXML, open your map file, click the Configure Transformation Scenarios button, and duplicate the DITA Map Webhelp output.
  9. Edit the copy, click the Parameters tab, and in the args.hdf option, browse to the XHTML file you created.
  10. When you create content, add platform="java" and such to your content. Users will be able to select the attributes they want.
  11. For the ditamap file, instead of addding platform="java", you must use outputclass="java". This is because the DITA OT processes the TOC differently from the rest of the content, and any platform/data tags get stripped out of the output.

About Tom Johnson

Tom Johnson

I'm an API technical writer based in the Seattle area. On this blog, I write about topics related to technical writing and communication — such as software documentation, API documentation, AI, information architecture, content strategy, writing processes, plain language, tech comm careers, and more. Check out my API documentation course if you're looking for more info about documenting APIs. Or see my posts on AI and AI course section for more on the latest in AI and tech comm.

If you're a technical writer and want to keep on top of the latest trends in the tech comm, be sure to subscribe to email updates below. You can also learn more about me or contact me. Finally, note that the opinions I express on my blog are my own points of view, not that of my employer.