6Navigation

This chapter shows how to create a document structure which represents a Navigation tree, how to assign it to the category tree and finally how to process it using a NaviItemBuilder to create a Navigation for the website.

Document structure

A new document type navigation is needed also to make sure that the document category handles category config tasks. The document types should look like this:

### Category #########

DocumentType;10244;category;Category
  viewname   ; string ; Viewname
  configs    ; list   ; Config tasks

### Category task #########

DocumentType;10245;configtask;Configtask
  type    ; int    ; Type
  info    ; string ; Info
  content ; list   ; Content

### Navigation #########

DocumentType;10246;navigation;Navigation
  title         ; string ; Title
  linkinternal  ; list   ; Internal Link
  linkexternal  ; string ; External URL
  linktype      ; int    ; Linktype
  linkparameter ; string ; Link parameter
  children      ; list   ; Children

Document types for navigation/category tasks/category from ADM-tools

Also declare the constants in the documentmodel.jsf (.../generator.std/includes/documentmodel.jsf)

  // =====================================================================
  public static final int RT_CATEGORY = 10244;

  public static final String PT_CATEGORY_VIEWNAME = "viewname";
  public static final String PT_CATEGORY_TASKS = "configs";

  // =====================================================================
  public static final int RT_CONFIGTASK = 10245;
  
  public static final String PT_CONFIGTASK_TYPE = "type";
  public static final String PT_CONFIGTASK_INFO = "info";
  public static final String PT_CONFIGTASK_CONTENT = "content";
  
  // =====================================================================
  public static final int RT_NAVIGATION = 10246;

  public static final String PT_NAVIGATION_TITLE = "title";
  public static final String PT_NAVIGATION_CHILDREN = "children";
  public static final String PT_REFERENCE_LINK_INTERNAL = "linkinternal";
  public static final String PT_REFERENCE_LINK_EXTERNAL = "linkexternal";
  public static final String PT_REFERENCE_LINK_TYPE = "linktype";
  public static final String PT_REFERENCE_LINK_PARAMETER = "linkparameter";

  // Also make sure that all Interface methods are properly filled

  // =====================================================================
  // from the ModelResourceConstantsAdapter to override  
  // =====================================================================
  public int    getRT_CATEGORY() { return RT_CATEGORY; }
  public int    getRT_CONFIGTASK() { return RT_CONFIGTASK; }
  public int    getRT_NAVIGATION() { return RT_NAVIGATION; }
  
  // supports CategoryModelAccess
  public String getPT_CATEGORY() { return PT_CATEGORY; }

  // supports category
  public String getPT_CATEGORY_VIEWNAME() { return PT_CATEGORY_VIEWNAME; }
  public String getPT_CATEGORY_CONFIGS() { return PT_CATEGORY_TASKS; }

  // supports category tasks (config tasks of the catgory)
  public String getPT_CONFIGTASK_TYPE() { return PT_CONFIGTASK_TYPE; }
  public String getPT_CONFIGTASK_DOCUMENTS() { return PT_CONFIGTASK_CONTENT; }

  // supports referenceables 
  public int[]  getRT_REFERENCEABLE() { return new int[] {RT_NAVIGATION}; }
  public String getPT_REFERENCE_LINK_INTERNAL() { return PT_REFERENCE_LINK_INTERNAL; }
  public String getPT_REFERENCE_LINK_EXTERNAL() { return PT_REFERENCE_LINK_EXTERNAL; }
  public String getPT_REFERENCE_LINK_TYPE() { return PT_REFERENCE_LINK_TYPE; }
  public String getPT_REFERENCE_LINK_PARAMETER() { return PT_REFERENCE_LINK_PARAMETER; }

  // supports NaviItemBuilder
  public String getPT_NAVIGATION_ELEMENTS() { return PT_NAVIGATION_CHILDREN; }
  public String getPT_NAVIGATION_HEADLINE() { return PT_NAVIGATION_TITLE; }
  

Navigation, Category and Config task constants in the documentmodel.jsf

Configtask configuration

Create a configtask.jsf to define constants for configuration task types (.../generator.std/includes/configtask.jsf).

<%@page import="app.cmsworks.cms.document.ErrorView,
                app.cmsworks.cms.document.DocumentModel,
                app.cmsworks.cms.document.CategoryModel
               "
        pageEncoding="UTF-8"
%><%!

/** Defines a list of constants to name the types of config tasks for categories
 */
public static class ConfigTask {
  
  final static int NO_TYPE = 0;
  final static int NAVI_ROOT = 10;
  final static int NAVI = 11;

  public static String getName(int id) {
    switch (id) {
      case NO_TYPE : return "no type";
      case NAVI_ROOT : return "Navi root";
      case NAVI : return "Navi";
    }
    return "unknown";
  }
  
  public static DocumentModel getTask(int type, CategoryModel cmCategory, ErrorView errors) throws Exception {
    return cmCategory.getTask(type, errors, getName(type));
  }

}

%>

Configtask types constant definition.

Declare the configuration task types in the editors desktop configuration q-custom.js (.../webui/cmsdesk.custom/<customer>/q-custom.js)

"document": {

  "configtask": {
    "type_prop": {
      xtype: "itwselectbox",
      options: [
        ["", "-- not selected --"],
        [ 10,"Navi root","Fill the one navigation root document in here."],
        [ 11,"Navi","Use a document of type navigation here."]
      ]
    }
  },

  "*": {
    "category_prop" : { // properties named category of type link shall be category input elements
      xtype: "itwcategory"
    },
    "linktype_prop": {  // a linktype property of a referenceable document type should be a dropdown from linktypes declared in an object sharedDefs
      xtype: "itwselectbox",
      options: sharedDefs.linkTypes
    }
  }

} // end document modification

Configtask type declarations in the editors desktop configuration q-custom.js

Documents in cmsWorks

The documents for the category tree, the navigation documents and the configtask document should be created and linked to each other like the graph in the adminstrators guide shows. We would suggest to place the documents Configtask right beside the category documents in the category tree within the editors desktop. It is advisable to create a dedicated folder for all navigation documents that is not part of the folder containing the content but rather created aside that folder.

The root category references a configtask "Navi root" containing the root of the navigation tree.

A category references a configtask "Navi" containing a navigation document representing this category.

A Navigation document references a content page which then is the (leaf) content page of the navigation.

Benefits of Navigation documents

At each level of the navigation tree the order of the children is manually set by the editor. It is possible to also add entries to target external URLs or even skip to assign a category to a navigation.

Maybe add a linklist medium to the document type to produce icons for navi entries.

Programming

<%@page import="
                app.cmsworks.cms.document.ErrorView,
                app.cmsworks.cms.document.HTMLErrorView,
                app.cmsworks.cms.document.DocumentModel,
                app.cmsworks.cms.document.CategoryModel,
                app.cmsworks.cms.document.CategoryModelAccess,
                
                app.cmsworks.cms.document.NaviItem,
                app.cmsworks.cms.document.NaviItemBuilder

               "
        session="false"
        contentType="text/html;charset=UTF-8"
%><%@include file="includes/documentmodel.jsf" 
%><%@include file="includes/configtask.jsf" 
%><%!

// creats a list of navi entries from the chidren of a given NaviItem
public String getNaviEntries(NaviItem niCur) throws Exception {
  if (niCur == null) return "";
  StringBuffer sb = new StringBuffer();
  for (NaviItem ni : niCur.getChildren()) {
    String cls = "";
    if (ni.isSelected()) {
      cls = " sel";
    }
    String entry = "<a class=\"nv" + cls + "\" " + ni.getLink().createAnchorTarget() + ">" + ni.getTitle() + "</a>";
    sb.append(entry);
  }
  return sb.toString();
}

%><%

ErrorView errors = new HTMLErrorView();
DocumentModel dmPage = null;
String htmlNavi = "";

//Fetch the sensible data
try {
  dmPage = new DocumentModel(request, new Types());
  errors.setPreview(dmPage);

  // Get the category from the page document
  CategoryModel cmCategory = new CategoryModelAccess(dmPage).getCategory(errors);

  // Get the navi root task from the category (or any parent category because this task is only defined in the category root) 
  DocumentModel dmNaviRootTask = ConfigTask.getTask(ConfigTask.NAVI_ROOT, cmCategory, errors);
  // Get the document Navigation representing the root of the navigation which itself is not part of the navigation
  DocumentModel dmNaviRoot = dmNaviRootTask.getLinkedResource(Types.PT_CONFIGTASK_CONTENT, Types.RT_NAVIGATION, 0, errors);
  
  // Use the NaviItemBuilder to create NaviItem objects in a tree 
  // where one item is selected and its parent and its grand parent and so on
  NaviItem niRoot = new NaviItemBuilder().createSelectedNaviItems(dmNaviRoot, dmPage, ConfigTask.NAVI, errors);

  StringBuffer sb = new StringBuffer();
  
  NaviItem niCur = niRoot;
  String htmlNaviItems = getNaviEntries(niCur);
  while (niCur != null && htmlNaviItems.length() > 0) {
    String cls = " lvl" + niCur.getLevel();
    sb.append("<div class=\"nvline" + cls + "\">");
    sb.append(htmlNaviItems);
    sb.append("</div>");
    // get the child that has the isSelected flag or null if no such child exist
    niCur = niCur.getSelectedChild();
    htmlNaviItems = getNaviEntries(niCur);
  }
  
  htmlNavi = sb.toString();
}
catch (Throwable t) {
  // In preview the errors will be shown from errors.render() 
  // but in live state this include returns an error code so in the page including this component is missing
  if (errors.exit(response, t, dmPage, this.getClass().getName())) {
    return;
  }
}
//Now start the HTML-Output
%><nav><%= htmlNavi %></nav><%= errors.render() %>

A Navigation is produces using NaviItemBuilder in a inc-navi.jsp

To include the navi into a page within a JSP "page-xyz.jsp" to render this page use

htmlNavi = new ContentInclude(dmPage, dmPage, "inc-navi.jsp", errors).getIncludeContent();

To select a NaviItem the NaviItemBuilder first tries to find the document (page) which currently rendered linked by any navigation document of the navigation tree.

If this is not found here, the NaviItemBuilder looks into the category to get a configuration task "Navi" and tries to find this navigation document in the navigation tree.

In case there is none, no selection is used and rendered.

The NaviItemBuilder uses the Referenceable interface to create a link from the four input fields (linkintern/linkextern/linktype/linkparameter).