docs: function(panels, patternData, iframePassback, switchText) {
  
      // set-up defaults
      var template, templateCompiled, templateRendered;
      var annotation, comment, count, div, els, item, markup, i;
      var patternPartial = patternData.patternPartial;
      patternData.panels = panels;
      
      // set a default pattern description for modal pop-up
      if (!iframePassback && (patternData.patternDesc.length === 0)) {
        patternData.patternDesc = "This pattern doesn't have a description.";
      }
  
      // capitilize the pattern name
      patternData.patternNameCaps = patternData.patternName.toUpperCase();
  
      // check for annotations in the given mark-up
      markup           = document.createElement('div');
      markup.innerHTML = patternData.patternMarkup;
  
      count = 1;
      patternData.annotations = [];
      delete patternData['patternMarkup'];
  
      for (i = 0; i < comments.comments.length; ++i) {
  
        item = comments.comments[i];
        els  = markup.querySelectorAll(item.el);
  
        if (els.length > 0) {
          annotation = { 'displayNumber': count, 'el': item.el, 'title': item.title, 'comment': item.comment };
          patternData.annotations.push(annotation);
          count++;
        }
  
      }
  
      // alert the pattern that annotations should be highlighted
      if (patternData.annotations.length > 0) {
        var obj = JSON.stringify({ 'event': 'patternLab.annotationsHighlightShow', 'annotations': patternData.annotations });
        document.getElementById('sg-viewport').contentWindow.postMessage(obj, panelsViewer.targetOrigin);
      }
  
      // add hasComma property to lineage
      if (patternData.lineage.length > 0) {
        for (i = 0; i < patternData.lineage.length; ++i) {
          if (i < (patternData.lineage.length - 1)) {
            patternData.lineage[i].hasComma = true;
          }
        }
      }
  
      // add hasComma property to lineageR
      if (patternData.lineageR.length > 0) {
        for (i = 0; i < patternData.lineageR.length; ++i) {
          if (i < (patternData.lineageR.length - 1)) {
            patternData.lineageR[i].hasComma = true;
          }
        }
      }
  
      // add *Exists attributes for Hogan templates
      // figure out if the description exists
      patternData.patternDescExists = ((patternData.patternDesc.length > 0) || ((patternData.patternDescAdditions !== undefined) && (patternData.patternDescAdditions.length > 0)));
  
      // figure out if lineage should be drawn
      patternData.lineageExists = (patternData.lineage.length !== 0);
  
      // figure out if reverse lineage should be drawn
      patternData.lineageRExists = (patternData.lineageR.length !== 0);
  
      // figure out if pattern state should be drawn
      patternData.patternStateExists = (patternData.patternState.length > 0);
      
      // figure if annotations should be drawn
      patternData.annotationExists = (patternData.annotations.length > 0);
      
      // figure if the entire desc block should be drawn
      patternData.descBlockExists = (patternData.patternDescExists || patternData.lineageExists || patternData.lineageRExists || patternData.patternStateExists || patternData.annotationExists);
      
      // set isPatternView based on if we have to pass it back to the styleguide level
      patternData.isPatternView = (iframePassback === false);
  
      // render all of the panels in the base panel template
      template         = document.getElementById('pl-panel-template-base');
      templateCompiled = Hogan.compile(template.innerHTML);
      templateRendered = templateCompiled.render(patternData);
  
      // make sure templateRendered is modified to be an HTML element
      div              = document.createElement('div');
      div.className    = 'sg-modal-content-inner';
      div.innerHTML    = templateRendered;
      templateRendered = div;
  
      // add click events
      templateRendered = panelsUtil.addClickEvents(templateRendered, patternPartial);
  
      // add onclick events to the tabs in the rendered content
      for (i = 0; i < panels.length; ++i) {
  
        panel = panels[i];
  
        // default IDs
        panelTab   = '#sg-'+patternPartial+'-'+panel.id+'-tab';
        panelBlock = '#sg-'+patternPartial+'-'+panel.id+'-panel';
  
        // show default options
        if ((templateRendered.querySelector(panelTab) !== null) && (panel.default)) {
          templateRendered.querySelector(panelTab).classList.add('sg-tab-title-active');
          templateRendered.querySelector(panelBlock).style.display = 'block';
        }
  
      }
  
      // find lineage links in the rendered content and add postmessage handlers in case it's in the modal
      $('#sg-code-lineage-fill a, #sg-code-lineager-fill a', templateRendered).on('click', function(e){
        e.preventDefault();
        var obj = JSON.stringify({ 'event': 'patternLab.updatePath', 'path': urlHandler.getFileName($(this).attr('data-patternpartial')) });
        document.getElementById('sg-viewport').contentWindow.postMessage(obj, panelsViewer.targetOrigin);
      });
  
      // gather panels from plugins
      Dispatcher.trigger('insertPanels', [templateRendered, patternPartial, iframePassback, switchText]);
  
    }