Class ::xowiki::includelet::toc

::xowiki::includelet::toc[i] create ... \
           [ -__decoration (default "plain") ] \
           [ -id id ] \
           [ -parameter_declaration (default " {-style ""} {-renderer ""} {-open_page ""} {-book_mode false} {-folder_mode false} {-ajax false} {-expand_all false} {-remove_levels 0} {-category_id} {-locale ""} {-orderby ""} {-source ""} {-range ""} {-allow_reorder ""} {-include_in_foldertree "true"} {-CSSclass_top_ul ""} {-CSSclass_ul ""} ") ]

Defined in

Class Relations

  • class: ::xowiki::IncludeletClass[i]
  • superclass: ::xowiki::Includelet[i]
  • instmixin: ::xowiki::includelet::PageReorderSupport[i]
::xowiki::IncludeletClass create ::xowiki::includelet::toc \
     -superclass ::xowiki::Includelet \
     -instmixin ::xowiki::includelet::PageReorderSupport

Methods (to be applied on the object)

  • anchor (scripted)

    # try to strip the language prefix from the name
    regexp {^.*:([^:]+)$} $name _ name
    # anchor is used between single quotes
    regsub -all ' $name {\'} anchor
    return $anchor

Methods (to be applied on instances)

  • __decoration (setter)

  • build_navigation (scripted)

    #
    # compute associative arrays open_node and navigation (position
    # and current)
    #
    :get_parameters
    array set :navigation {position 0 current ""}
    
    # the top node is always open
    set :open_node() true
    set node_cnt 0
    foreach o [$pages children] {
      $o instvar page_order name
      incr node_cnt
      set :page_name($node_cnt$name
      if {![regexp {^(.*)[.]([^.]+)} $page_order _ parent]} {set parent ""}
      #
      # If we are on the provided $open_page, we remember our position
      # for the progress bar.
      set on_current_node [expr {$open_page eq $name} ? "true" : "false"]
      if {$on_current_node} {
        set :navigation(position) $node_cnt
        set :navigation(current) $page_order
      }
      if {$expand_all} {
        set :open_node($page_order) true
      } elseif {$on_current_node} {
        set :open_node($page_order) true
        # make sure to open all nodes to the root
        for {set p $parent} {$p ne ""} {} {
          set :open_node($p) true
          if {![regexp {^(.*)[.]([^.]+)} $p _ p]} {set p ""}
        }
      }
    }
    set :navigation(count) $node_cnt
    #:log OPEN=[lsort [array names :open_node]]
  • build_toc (scripted)

     <instance of xowiki::includelet::toc[i]> build_toc

    Testcases:
    includelet_toc, xowiki
    :get_parameters
    array set :navigation {parent "" position 0 current ""}
    
    set extra_where_clause ""
    if {[info exists :category_id]} {
      lassign [:category_clause ${:category_id}] cnames extra_where_clause
    }
    lassign [::xowiki::Includelet locale_clause -revisions p -items p $package_id $locale]  locale locale_clause
    #:msg locale_clause=$locale_clause
    set order_direction asc
    set order_attribute page_order
    
    if {$source ne ""} {
      :get_page_order -source $source
      set page_order_clause "and name in ([ns_dbquotelist [array names :page_order]])"
      set page_order_att ""
    } elseif {$orderby ne ""} {
      lassign [split $orderby ,] order_attribute order_direction
      if {$order_attribute ni {page_order title}} {
        ns_log warning "toc includelet: ignore invalid page order '$orderby'"
        set order_attribute page_order
        set order_direction asc
        set page_order_att "page_order,"
        set page_order_clause "and not page_order is NULL"
      } else {
        set page_order_att "page_order,"
        set page_order_clause ""
        append extra_where_clause " and page_id != [${:__including_page} revision_id]"
      }
    } else {
      set page_order_clause "and not page_order is NULL"
      set page_order_att "page_order,"
    }
    
    if {$folder_mode} {
      # TODO just needed for Michael Aram?
      set parent_id [${:__including_page} item_id]
    } else {
      #set parent_id [::$package_id folder_id]
      set parent_id [${:__including_page} parent_id]
    }
    
    set sql [::xo::dc select  -vars "page_id, $page_order_att name, title"  -from "xowiki_page_live_revision p"  -where "parent_id = :parent_id  $page_order_clause  $extra_where_clause $locale_clause"]
    set pages [::xowiki::Page instantiate_objects -sql $sql]
    
    #
    # Set the mixin for page-order before the call of __value_compare.
    # Probably, we should use here a different approach to support as well
    # sorting by different attributes.
    #
    $pages orderby  -order [expr {$order_direction in {asc ""} ? "increasing" : "decreasing"}]  -type [ad_decode $order_attribute page_order index dictionary]  $order_attribute
    
    if {$range ne "" && $page_order_att ne ""} {
      lassign [split $range -] from to
      foreach p [$pages children] {
        if {[$pages __value_compare [$p set page_order] $from 0] == -1
            || [$pages __value_compare [$p set page_order] $to 0] > 0} {
          $pages delete $p
        }
      }
    }
    
    if {$source ne ""} {
      # add the page_order to the objects
      foreach p [$pages children] {
        $p set page_order [set :page_order([$p set name])]
      }
    }
    
    return $pages
  • cache_includelet_data (scripted)

    append data  [list :array set navigation [array get :navigation]] \n  [list :array set page_name [array get :page_name]] \n
    return $data
  • count (scripted)

    return [set :navigation(count)]
  • current (scripted)

    return [set :navigation(current)]
  • href (scripted)

    if {$book_mode} {
      set href [::${:package_id} url]#[toc anchor $name]
    } else {
      set href [::${:package_id} pretty_link -parent_id [${:__including_page} parent_id] $name]
    }
    return $href
  • id (setter)

  • include_head_entries (scripted)

    switch -- ${:renderer} {
      yuitree {
        ::xowiki::Tree include_head_entries -renderer yuitree -style ${:style}
      }
      list    {
        :get_parameters
        set tree_renderer [expr {$allow_reorder eq "" ? "list" : "listdnd"}]
        ::xowiki::Tree include_head_entries -renderer $tree_renderer -style ${:style}
      }
      none {}
    }
  • initialize (scripted)

     <instance of xowiki::includelet::toc[i]> initialize

    Testcases:
    includelet_toc, xowiki
    :get_parameters
    array set :navigation {count 0 position 0 current ""}
    set list_mode 0
    dict set :render_properties CSSclass_ul $CSSclass_ul
    dict set :render_properties CSSclass_top_ul $CSSclass_top_ul
    
    #
    # If there is no renderer specified, determine the renderer from
    # the (provided) style. When the render is explicitly specified,
    # use it for rendering.
    #
    if {$renderer eq ""} {
      switch -- $style {
        "menu"    {set renderer yuitree}
        "folders" {set renderer yuitree}
        "yuitree" {set renderer "yuitree"}
        "list"    {set style ""set list_mode 1; set renderer list}
        "none"    {set style ""set renderer none}
        "default" {set style ""set list_mode 1; set renderer list
          #
          # Fall back to "xowiki-tree" for "CSSclass_ul" only when
          # value was not specified as a parameter.
          #
          if {$CSSclass_ul eq ""} {
            dict set :render_properties CSSclass_ul xowiki-tree
          }
        }
      }
      set :use_tree_renderer 0
    } else {
      set :use_tree_renderer 1
    }
    
    set :include_in_foldertree $include_in_foldertree
    set :renderer $renderer
    set :style $style
    set :list_mode $list_mode
    set :book_mode $book_mode
  • page_name (scripted)

    return [set :page_name($p)]
  • page_number (scripted)

    #:log "o: $page_order"
    set displayed_page_order $page_order
    for {set i 0} {$i < $remove_levels} {incr i} {
      regsub {^[^.]+[.]} $displayed_page_order "" displayed_page_order
    }
    return $displayed_page_order
  • parameter_declaration (setter)

  • parent_id (scripted)

    ${:__including_page} parent_id
  • position (scripted)

    return [set :navigation(position)]
  • render (scripted)

     <instance of xowiki::includelet::toc[i]> render

    Testcases:
    includelet_toc, xowiki
    :get_parameters
    
    if {![info exists :id]} {
      set :id [::xowiki::Includelet html_id [self]]
    }
    if {[info exists category_id]} {
      set :category_id $category_id
    }
    
    #
    # Collect the pages which are either children of the page, or
    # children of the parent of the page depending on "folder_mode".
    #
    set pages [:build_toc $package_id $locale $source $range]
    
    #foreach p [$pages children] {
    #  ns_log notice "... [$p set page_order] [$p set name]"
    #}
    
    #
    # Build the general navigation structure using associative arrays
    #
    :build_navigation $pages
    #
    # Call a render on the created structure
    #
    if {[nsf::is object ::__xowiki__MenuBar] && ${:include_in_foldertree}} {
      ::__xowiki__MenuBar additional_sub_menu -kind folder -pages $pages -owner [self]
    }
    #
    # TODO: We should call here the appropriate tree-renderer instead
    # of the toc-specific renderers, but first we have to check, if
    # these are fully feature-compatible.
    #
    #:log "=== toc render with <${:renderer}> treerenderer ${:use_tree_renderer} list_mode <${:list_mode}>"
    if {${:renderer} eq "none"} {
    } elseif {${:use_tree_renderer}} {
      return [:render_tree -full 1 $pages]
    } elseif {${:list_mode}} {
      return [:render_list $pages]
    } else {
      return [:render_yui_list -full true $pages]
    }
  • render_list (scripted)

     <instance of xowiki::includelet::toc[i]> render_list

    Testcases:
    includelet_toc, xowiki
    :get_parameters
    
    #
    # Build a reduced toc tree based on pure HTML (no JavaScript or
    # AJAX involved).  If an open_page is specified, produce an as
    # small as possible tree and omit all non-visible nodes.
    #
    if {$open_page ne ""} {
      # TODO: can we allow open_page and reorder?
      set allow_reorder ""
    } else {
      set allow_reorder [:page_reorder_check_allow -with_head_entries false $allow_reorder]
    }
    set tree [::xowiki::Tree new -id [:id] -destroy_on_cleanup]
    $tree array set open_node [array get :open_node]
    $tree add_pages -full $full  -remove_levels $remove_levels  -book_mode $book_mode -open_page $open_page -expand_all $expand_all  -owner [self]  -properties ${:render_properties}  $pages
    
    if {$allow_reorder ne ""} {
      :page_reorder_init_vars -allow_reorder $allow_reorder js last_level ID min_level
      #set js "\nYAHOO.xo_page_order_region.DDApp.package_url = '[::$package_id package_url]';"
      set HTML [$tree render -style listdnd -context [list min_level $min_level]]
    } else {
      set HTML [$tree render -style list -properties ${:render_properties}]
    }
    
    return $HTML
  • render_tree (scripted)

    :get_parameters
    set tree [::xowiki::Tree new  -id [:id]  -verbose 0  -owner [self]  -destroy_on_cleanup]
    $tree array set open_node [array get :open_node]
    $tree add_pages -full $full -remove_levels $remove_levels  -book_mode $book_mode -open_page $open_page  -owner [self]  $pages
    
    if {$allow_reorder ne ""} {
      set allow_reorder [:page_reorder_check_allow -with_head_entries false $allow_reorder]
    }
    
    if {$allow_reorder ne ""} {
      :page_reorder_init_vars -allow_reorder $allow_reorder js last_level ID min_level
      #:log "=== call tree render [list $tree render -style listdnd] min_level=$min_level"
      set HTML [$tree render -style listdnd -context [list min_level $min_level]]
    } else {
      set HTML [$tree render -style list]
    }
    #:log "render_tree HTML  => $HTML"
    return $HTML
  • render_yui_list (scripted)

     <instance of xowiki::includelet::toc[i]> render_yui_list

    Testcases:
    includelet_toc, xowiki
    :get_parameters
    
    #
    # Render the tree with the yui widget (with or without ajax)
    #
    if {$book_mode} {
      #:log "--warn: cannot use bookmode with ajax, resetting ajax"
      set ajax 0
    }
    set :ajax $ajax
    
    if {$ajax} {
      set :js [:yui_ajax]
    } else {
      set :js [:yui_non_ajax]
    }
    
    set tree [::xowiki::Tree new -id [:id] -destroy_on_cleanup]
    $tree array set open_node [array get :open_node]
    $tree add_pages -full $full -remove_levels $remove_levels  -book_mode $book_mode -open_page $open_page -expand_all $expand_all  -owner [self]  $pages
    
    set HTML [$tree render -style yuitree -js ${:js}]
    return $HTML
  • yui_ajax (scripted)

    return "var [:js_name] = {
    
         count: [set :navigation(count)],
    
         getPage: function(href, c) {
             //console.log('getPage: ' + href + ' type: ' + typeof href) ;
    
             if ( typeof c == 'undefined' ) {
    
                 // no c given, search it from the objects
                 // console.log('search for href <' + href + '>');
    
                 for (i in this.objs) {
                     if (this.objs\[i\].ref == href) {
                        c = this.objs\[i\].c;
                        // console.log('found href ' + href + ' c=' + c);
                        var node = this.tree.getNodeByIndex(c);
                        if (!node.expanded) {node.expand();}
                        node = node.parent;
                        while (node.index > 1) {
                            if (!node.expanded) {node.expand();}
                            node = node.parent;
                        }
                        break;
                     }
                 }
                 if (typeof c == 'undefined') {
                     // console.warn('c undefined');
                     return false;
                 }
             }
             //console.log('have href ' + href + ' c=' + c);
    
             var transaction = YAHOO.util.Connect.asyncRequest('GET',  href + '?template_file=view-page&return_url=' + encodeURI(href),
                {
                  success:function(o) {
                     var bookpage = document.getElementById('book-page');
                  var fadeOutAnim = new YAHOO.util.Anim(bookpage, { opacity: {to: 0} }, 0.5 );
    
                     var doFadeIn = function(type, args) {
                        // console.log('fadein starts');
                        var bookpage = document.getElementById('book-page');
                        bookpage.innerHTML = o.responseText;
                        var fadeInAnim = new YAHOO.util.Anim(bookpage, { opacity: {to: 1} }, 0.1 );
                        fadeInAnim.animate();
                     }
    
                     // console.log(' tree: ' + this.tree + ' count: ' + this.count);
                     // console.info(this);
    
                     if (this.count > 0) {
                        var percent = (100 * o.argument.count / this.count).toFixed(2) + '%';
                     } else {
                        var percent = '0.00%';
                     }
    
                     if (o.argument.count > 1) {
                        var link = o.argument.href;
                        var src = '/resources/xowiki/previous.png';
                        var onclick = 'return [:js_name].getPage(\"' + link + '\");' ;
                     } else {
                        var link = '#';
                        var onclick = '';
                        var src = '/resources/xowiki/previous-end.png';
                     }
    
                     // console.log('changing prev href to ' + link);
                     // console.log('changing prev onclick to ' + onclick);
    
                     document.getElementById('bookNavPrev.img').src = src;
                     document.getElementById('bookNavPrev.a').href = link;
                     document.getElementById('bookNavPrev.a').setAttribute('onclick',onclick);
    
                     if (o.argument.count < this.count) {
                        var link = o.argument.href;
                        var src = '/resources/xowiki/next.png';
                        var onclick = 'return [:js_name].getPage(\"' + link + '\");' ;
                     } else {
                        var link = '#';
                        var onclick = '';
                        var src = '/resources/xowiki/next-end.png';
                     }
    
                     // console.log('changing next href to ' + link);
                     // console.log('changing next onclick to ' + onclick);
                     document.getElementById('bookNavNext.img').src = src;
                     document.getElementById('bookNavNext.a').href = link;
    
                     document.getElementById('bookNavNext.a').setAttribute('onclick',onclick);
                     document.getElementById('bookNavRelPosText').innerHTML = percent;
                     //document.getElementById('bookNavBar').setAttribute('style', 'width: ' + percent + ';');
                     document.getElementById('bookNavBar').style.width = percent;
    
                     fadeOutAnim.onComplete.subscribe(doFadeIn);
               fadeOutAnim.animate();
                  },
                  failure:function(o) {
                     // console.error(o);
                     // alert('failure ');
                     return false;
                  },
                  argument: {count: c, href: href},
                  scope: [:js_name]
                }, null);
    
                return false;
            },
    
         treeInit: function() {
            [:js_name].tree = new YAHOO.widget.TreeView('[:id]');
            [:js_name].tree.subscribe('clickEvent', function(oArgs) {
              var m = /href=\"(\[^\"\]+)\"/.exec(oArgs.node.html);
              [:js_name].getPage( m\[1\], oArgs.node.index);
            });
            [:js_name].tree.draw();
         }
    
      };
    
     YAHOO.util.Event.addListener(window, 'load', [:js_name].treeInit);
    "
  • yui_non_ajax (scripted)

    return "
      var [:js_name];
      YAHOO.util.Event.onDOMReady(function() {
         [:js_name] = new YAHOO.widget.TreeView('[:id]');
         [:js_name].subscribe('clickEvent',function(oArgs) {
            //console.info(oArgs);
            var m = /href=\"(\[^\"\]+)\"/.exec(oArgs.node.html);
            //console.info(m\[1\]);
            //window.location.href = m\[1\];
            return false;
    });
        [:js_name].render();
      });
     "