Search results

DITA: Add an expanding side pane (Sidr)

You can add a sliding side panel that appears when someone clicks a link. This is particularly useful for code samples where you want to elaborate more with comments but don't have the space to do so.

For a demo of this functionality, see the Sidr pane demo here.

Although there are a variety of jQuery sidebar plugins, the Sidr works pretty well. It allows you to easily call different menus, and arrange the panel to appear on the left or right. The original purpose of Sidr was to act as a menu for mobile devices that don't have much screen real estate, but it works well in other situations too.

The particular scenario where I think this functionality is critical is with code samples. With code samples, you're limited to about 2 lines of comments per 5-10 lines of code. But a lot of the stuff that's going on in code is really complicated and warrants more extensive elaboration. This is where the side panel comes in really handy. You can elaborate as much as you want in the expanding side panels.

Integrating this plugin permanently alters the OxygenXML webhelp (though not visible, just in the scripts that are loaded and source code IDs) so make a backup of your files before committing changes. Also, the method described below is just one way of integrating the plugin, not the only way.

Integrate Sidr into OxygenXML

To integrate the Sidr plugin into OxygenXML:

  1. Go to the http://www.berriart.com/sidr/ and click the Download button.
  2. From the downloaded zip file, open the jquery.sidr.min.js file and copy its contents.
    The CSS file is minified. If you paste it into Oxygen and then click the format/indent button, it will de-minify the file.
  3. In a text editor, open the JavaScript file located here: [Oxygen Install Directory]/frameworks/dita/DITA-OT/plugins/com.oxygenxml.webhelp/oxygen-webhelp/resources/js/webhelp_topic.js.
  4. Insert the copied script at the bottom right before the closing });.
  5. Open one of the CSS files, such as jquery.sidr.light.css and copy its contents.
  6. In a text editor, open the CSS file located here: [Oxygen Install Directory]/frameworks/dita/DITA-OT/plugins/com.oxygenxml.webhelp/oxygen-webhelp/resources/css/webhelp_topic.css.
  7. Insert the styles near the bottom of the stylesheet.
  8. If desired, you can add some more styles to customize the side pane display. Much of the default styling is for a navigation menu. This means if you add ul and li tags, your content will look like a navigation menu rather than a list, so you may want remove some of the unncessary styles. Additionally, you may want to add a few styles of your own. Here are some styles I've added:
    .sidr{
        background-color:whitesmoke;
        box-shadow:none;
    }
    .closeMe {
        display:none;
    }
    .sidr > .closeMe{
        display:block;
        padding:<span class="hl-number">5</span>px;
        background-color:whitesmoke;
        border:<span class="hl-number">1</span>px solid #C0C0C0;
        font-size:<span class="hl-number">11</span>px;
        float:right;
        margin-right:<span class="hl-number">5</span>px;
    }
    
    .closeMe:hover{
        display:none;
    }
    
    .sidr > .closeMe:hover{
        display:block;
        background-color:#F5F5F5;
    }
    
    div.sidr h2.sectiontitle {
        font-size:<span class="hl-number">15</span>px;
        background-color: whitesmoke;
    }
    
    .sidr p.sphead {
        font-size:<span class="hl-number">14</span>px;
        font-weight:bold;
        padding-top:<span class="hl-number">12</span>px;
        padding-bottom:<span class="hl-number">3</span>px;
    }
    
    p.sphead {
        font-size:<span class="hl-number">16</span>px;
        padding-top:<span class="hl-number">12</span>px;
        padding-bottom:<span class="hl-number">3</span>px;
        color: #<span class="hl-number">444</span>;
    }
    .codeblock a{
        font-style:italic;
        color:#<span class="hl-number">458</span>B00;
    }
    
    .codeblock a:hover{
        color:#<span class="hl-number">78</span>AB46;
    }
    
    pre{
        padding:<span class="hl-number">0.5</span>em;
        background-color:#EEE;
        overflow:auto;
        max-height:<span class="hl-number">2000</span>px;
        margin:<span class="hl-number">0.5</span>em;
    }
                        

    The closeMe style is for a close button that will appear at the bottom of the pane. The p.sphead style is for a section subheading style. Note that even though you will later be giving custom names to your side panels, the script will always inject sidr as a class into the panel. The other styling is for links inside codeblock elements. Also, since I intend to document long code blocks with this method, I wanted to lengthen the code block area beyond the default 600px (otherwise for code longer than 600px you have to use scroll bars to see the full content).

Allow IDs to pass through

By default, attributes you add to content, such as id="sidepanel_1" won't appear in DITA's webhelp output (they're stripped out entirely). We need to hack Oxygen's webhelp files to allow these tags to pass through.
  1. In a text editor, open the file located here: [Oxygen Install Directory]/frameworks/dita/DITA-OT/plugins/org.dita.xhtml/xsl/xslhtml/dita2htmllmpl.xsl.
  2. Find 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. You can add other attributes that you want to pass through here as well (such as product) depending on what you plan to use.

    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.

Add functions to trigger Sidr

Now you need to add some functions to your webhelp_topic.js file to trigger the Sidr plugin to open the side panel.
  1. Add the following functions to your webhelp_topic.js file (located here: [Oxygen Install Directory]/frameworks/dita/DITA-OT/plugins/com.oxygenxml.webhelp/oxygen-webhelp/resources/js/webhelp_topic.js):
    $(<span class="hl-string" style="color:#2a00ff">'.demo_sidepanel_1'</span>).sidr( {
        name:<span class="hl-string" style="color:#2a00ff">'fullcode__demo_sidepanel_1'</span>,
        side:<span class="hl-string" style="color:#2a00ff">'left'</span>
        });
    
    $(<span class="hl-string" style="color:#2a00ff">'.demo_sidepanel_2'</span>).sidr( {
        name:<span class="hl-string" style="color:#2a00ff">'fullcode__demo_sidepanel_2'</span>,
        side:<span class="hl-string" style="color:#2a00ff">'left'</span>
        });
                    

    The $('.demo_sidepanel_1').sidr() means that we are binding the sidr function to an element that has a class of demo_sidepanel_1. You can pass the sidr function a variety of parameters, but for the most part you need only to specify the side panel name that you want to open. (By default, the panel already opens on the left. I made this parameter explicit as an example of how to pass multiple parameters into the function.)

    The panel name is the element ID of the section you want to display in the side panel. I'll explain this a bit more later, but note that "fullcode" is the topic ID of the page where the side panel appears. Although later in the code you will see that the section ID in the topic is merely "demo_sidepanel_1", upon rendering the webhelp, DITA adds the topic ID (in my sample, the topic ID is fullcode) before the section name. DITA does this for the section element but not others (not sure why -- section is just special).

  2. Add the following closing scripts to the same webhelp_topic.js file. These functions close the side panel.
    $('.close_demo_sidepanel_1').click(function(event) {
    event.preventDefault();
      $.sidr('close', 'fullcode__demo_sidepanel_1');
    });
    
    $('.close_demo_sidepanel_2').click(function(event) {
    event.preventDefault();
      $.sidr('close', 'fullcode__demo_sidepanel_2');
    });
                

    In this code, a click event is bound to an element with the close_demo_sidebar_1 class. The event.preventDefault() keeps the code from trying to open a new window and instead allows the sidr function to fire. Two arguments are passed to the sidr function: the method we want the function to run: close, and the name of the side panel we want to close: demo_sidepanel_1.

    By the way, the panel names (fullcode__demo_sidepanel_1) and classes (.demo_sidepanel_1) are completely customizable -- they're just what I've chosen to integrate for this demo.

    Note that the selector is a class rather than an ID. This is because when you transclude topics in DITA, the ID on the transcluded source gets changed when it is pulled into the transcluded target. Fortunately the DITA OT leaves the classes alone.

Add content in your topic

Now it's time to start adding your panel content in a DITA topic.
  1. Create a DITA concept topic and insert some triggers inside a code block like this:
     <section>
        <codeblock>
         this is some code
         this is some code
         this is some code
         this is some code
         this is some code
         this is some code
         this is some code
    
         // this is a comment with a brief explanation. <xref href="javascript();" scope="external" format="html" outputclass="demo_sidepanel_1"> &#187; more</xref>
    
         this is some code
         this is some code
         this is some code
         this is some code
         this is some code
         this is some code
         this is some code
             // this is a comment with a brief explanation. <xref href="javascript();" scope="external" format="html" outputclass="demo_sidepanel_2">&#187; more</xref>
                    

    It's important to note a few things here. For links in the codeblock, you can't use # for the href target, so use javascript();. (If your page ever fails to open the side pane but rather tries to open a new tab at javascript();, then you know something isn't working right in the way the script is triggered.)

    With each link, you must add the outputclass that correlates with the side panel name you want to open. In this example, the link with the class of demo_sidepanel_1 will open the element with the ID name of fullcode__sidepanel_1. The class and ID don't need to be the same -- you could have link with a class of tom that opens a panel named awesome, but just be sure you have these names set up in your webhelp_topic.js file. It depends on how you set up the triggers and menus in the jQuery scripts that you configured previously.

    (In fact, now might be a good time to review the scripts you added in previous steps to the webhelp_topic.js file to get a better understanding of how this all fits together.)

  2. Add the following for your side panel content:
      <section id="demo_sidepanel_1"><title>Side panel 1</title>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non tempor odio, eu scelerisque nunc. Fusce tincidunt magna nec nisl accumsan, a rhoncus tellus semper. Phasellus at turpis in risus elementum sollicitudin.</p>
          <p>Praesent commodo bibendum nisl id malesuada. Fusce id ligula ultricies, gravida risus ac, dictum magna. Quisque semper, dui quis dictum scelerisque, dui purus dapibus orci, suscipit facilisis nisi quam laoreet diam.</p>
          <p outputclass="sphead">Subhead</p>
          <p>Aenean turpis augue, elementum sit amet ultricies ullamcorper, placerat a lorem. Nullam vitae laoreet ipsum, a elementum ipsum. Cras venenatis felis blandit euismod euismod. Morbi venenatis lacus eu tellus molestie, in pulvinar quam porttitor. </p>
          <p>Aenean congue euismod orci, quis laoreet est hendrerit ac. Fusce gravida ligula et orci ornare, id semper ante pellentesque. Pellentesque suscipit sapien libero, quis consequat orci dapibus a. Mauris et dui ut lacus volutpat mollis consequat ut orci. Donec accumsan metus dolor, a sodales felis sagittis eget. Integer facilisis enim non fermentum bibendum.</p>
          <xref href="javascript();" scope="external" format="html" outputclass="closeMe" id="close_demo_sidepanel_1">Close</xref>
    
         </section>                        

    Here we add an ID attribute to the section element. Note that the menu name in the jQuery scripts is fullcode_demo_sidepanel_1, but the ID here is just written as demo_sidepanel_1. This is because the DITA OT will automatically prepend the topic ID and two underscores before the section ID. My topic ID happens to be fullcode, so that's why the jQuery scripts will look for fullcode__demo_sidepanel_1 as the name of the sidepanel instead of just demo_sidepanel_1. Again, I have no idea why the DITA OT does this.

    Render your content into webhelp and experiment with the trigger. If the link opens up a new page, it's because something isn't configured right. Usually it means the class on the more link doesn't align with the selector in the jQuery script. If the side panel opens but is blank, it's because the the menu name in the jQuery scripts doesn't match the menu name on the page. Look in your source code to see if the DITA OT is doing some funky shake and bake with the menu name.

Transcluding content from another page

If you want to transclude content from another page into your menus, so don't want to repeat the same content in multiple places, you can do so. When you transclude content from another source, you add the ID in the transclusion target, not the transclusion source (this caused me quite a bit of consternation at first...).
  1. Create a separate topic and add the following:
    <section id="demo_sidepanel_2"><title>Side panel 2</title>
       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non tempor odio, eu scelerisque nunc. Fusce tincidunt magna nec nisl accumsan, a rhoncus tellus semper. Phasellus at turpis in risus elementum sollicitudin.</p>
       <p>Praesent commodo bibendum nisl id malesuada. Fusce id ligula ultricies, gravida risus ac, dictum magna. Quisque semper, dui quis dictum scelerisque, dui purus dapibus orci, suscipit facilisis nisi quam laoreet diam.</p>
       <p outputclass="sphead">Subhead</p>
       <p>Aenean turpis augue, elementum sit amet ultricies ullamcorper, placerat a lorem. Nullam vitae laoreet ipsum, a elementum ipsum. Cras venenatis felis blandit euismod euismod. Morbi venenatis lacus eu tellus molestie, in pulvinar quam porttitor. </p>
       <p>Aenean congue euismod orci, quis laoreet est hendrerit ac. Fusce gravida ligula et orci ornare, id semper ante pellentesque. Pellentesque suscipit sapien libero, quis consequat orci dapibus a. Mauris et dui ut lacus volutpat mollis consequat ut orci. Donec accumsan metus dolor, a sodales felis sagittis eget. Integer facilisis enim non fermentum bibendum.</p>
       <xref href="javascript();" scope="external" format="html" outputclass="closeMe close_demo_sidepanel_2">Close</xref>
    
      </section>
                        

    Let's say the topic ID of this page is trans123.

  2. Now go to the page where you want to transclude the content (presumably, the page with the long code block that we've been working with already). Add a conref element where you want to insert the content:
     <section conref="transclusion_test.dita#trans123/demo_sidepanel_2" id="demo_sidepanel_2"/>
                      

    If you're transcluding content from a standalone topic to a side panel display, you'll no doubt want to style the section headers a bit differently. That's what this style is all about:

      div.sidr h2.sectiontitle {
        font-size:15px;
        background-color: whitesmoke;
    }
                            

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.