Class ::xowiki::includelet::references-graph

::xowiki::includelet::references-graph[i] create ... \
           [ -__decoration (default "none") ] \
           [ -parameter_declaration (default " {-folder .} {-page ""} {-link_type link} {-rankdir LR} {-fontsize 12} ") ]

Include a graph of the (partial) link structure in a wiki, starting either with a page or a folder. When a page is provided, the local link structure of this page is visualized (including incoming and outgoing links of the page; e.g. -page "." for the current page). Alternatively, the content of a folder can be shown.
Documented Parameters:
page
starting page for a partial link graph, provided as item ref
folder
starting page for showing all children of a folder (default .)
rankdir
possible values LR, TB, BT, or RL
fontsize
fontsize for graphviz (default 12)
Defined in packages/xowiki/tcl/references-graph-procs.tcl

Class Relations

  • class: ::xowiki::IncludeletClass[i]
  • superclass: ::xowiki::Includelet[i]
::xowiki::IncludeletClass create ::xowiki::includelet::references-graph \
     -superclass ::xowiki::Includelet

Methods (to be applied on instances)

  • __decoration (setter)

  • parameter_declaration (setter)

  • render (scripted)

    :get_parameters
    if {$page ne ""} {
        set page_info [$package_id item_ref  -default_lang en  -parent_id [${:__including_page} item_id]  $folder]
        set item_id [dict get $page_info item_id]
        if {$item_id eq "0"} {
            error "cannot locate page $page"
        }
        set incoming [xo::dc list _ [subst {
            select distinct page from xowiki_references
            where reference = :item_id
            and link_type = :link_type
        }]]
        set items [lsort -unique [list $item_id {*}$incoming]]
        #ns_log notice "=== PAGE item_id $item_id incoming $incoming items $items"
    
    } else {
        set folder_info [$package_id item_ref  -default_lang en  -parent_id [${:__including_page} item_id]  $folder]
        set parent_id [dict get $folder_info item_id]
        if {$parent_id eq "0"} {
            error "cannot locate folder $folder"
        }
        set parent_object [::xo::db::CrClass get_instance_from_db -item_id $parent_id]
        if {![$parent_object is_folder_page]} {
            ns_log notice "get parent_id from parent"
            set parent_id [$parent_object parent_id]
        }
        #
        # Get all pages (item_ids) under parent_id relevant for the
        # link graph. In case, there are references to pages outside
        # this set, these pages are treated as "extern"
        #
        #ns_log notice "folder $folder, parent_id $parent_id"
        set items [xo::dc list _ {
            select item_id from cr_items where parent_id = :parent_id}]
        if {[llength $items] == 0} {
            return "No pages under $folder could be found"
        }
    }
    #
    # Get all references outgoing from these item_ids.
    #
    set references [xo::dc list _ [subst {
        select distinct reference from xowiki_references
        where page in ([ns_dbquotelist $items])
        and link_type = :link_type
    }]]
    set extern [lmap ref $references {if {$ref in $items} continue; set ref}]
    set all [lsort -unique [concat $items $extern]]
    
    #
    # Get all unresolved outgoing references from these item_ids.
    #
    set unresolved_references [xo::dc list_of_lists _ [subst {
        select page, name, parent_id from xowiki_unresolved_references
        where page in ([ns_dbquotelist $items])
        and link_type = :link_type
    }]]
    
    #ns_log notice "items [lsort $items]"
    #ns_log notice "extern [lsort $extern]"
    #ns_log notice "all [lsort $all]"
    #ns_log notice "unresolved [lsort $unresolved_references]"
    
    foreach tuple [xo::dc list_of_lists _ [subst {
        select ci.item_id, ci.name, ci.parent_id, cr.title, o.package_id
        from cr_items ci, cr_revisions cr, acs_objects o
        where ci.latest_revision = cr.revision_id
        and cr.item_id in ([ns_dbquotelist $all])
        and cr.item_id = o.object_id
    }]] {
        lassign $tuple item_id name parent_id title package_id
        dict set item_info $item_id name $name
        #ns_log notice "dict set item_info $item_id name $name"
        dict set item_info $item_id title $title
        dict set item_info $item_id package_id $package_id
        dict set item_info $item_id parent_id $parent_id
    }
    
    foreach i $all {
        if {[dict get $item_info $i parent_id] ne $parent_id} {
            dict set item_info $i extern 1
            ns_log notice "dict set item_info $i extern 1"
        }
    }
    
    set edges {}
    set nodes {}
    
    foreach pair [xo::dc list_of_lists _ [subst {
        select reference, page from xowiki_references
        where page in ([ns_dbquotelist $items])
        and link_type = :link_type
    }]] {
        lassign $pair reference page
        set key havelink($page,$reference)
        if {![info exists $key]} {
            set from       [dict get $item_info $page name]
            set from_label [dict get $item_info $page name]
            set to         [dict get $item_info $reference name]
            set to_label   [dict get $item_info $reference name]
    
            #set to_label   [dict get $item_info $reference title]
            #set from_label [dict get $item_info $page title]
            if {[dict exists $item_info $reference extern]} {
                #
                # We have an "external" reference, i.e. a
                # reference to some other wiki page, which is not
                # in the set under the provided parent_id.
                #
                ns_log notice "EXTERN reference from $page $from to $reference $to"
    
                #
                # Maybe we have to initialize a different package as well
                #
                set reference_package_id [dict get $item_info $reference package_id]
                if {$reference_package_id ne $package_id} {
                    ::xo::Package initialize  -package_id $reference_package_id  -init_url false -keep_cc true
                }
                set targetObj [::xo::db::CrClass get_instance_from_db -item_id $reference]
                set to_label [$targetObj pretty_link]
                set shape box
            } else {
                set targetObj [::xo::db::CrClass get_instance_from_db -item_id $reference]
                set shape ellipse
            }
            set pageObj [::xo::db::CrClass get_instance_from_db -item_id $page]
            set pageUrl [$pageObj pretty_link]
            set referenceUrl [$targetObj pretty_link]
            append nodes [subst {"n$page" \[label="$from_label", fontsize=$fontsize, URL=\"$pageUrl\" \] \n}]
            append nodes [subst {"n$reference" \[label="$to_label", fontsize=$fontsize, URL=\"$referenceUrl\", shape=$shape\] \n}]
            append edges [subst {"n$page" -> "n$reference"\n}]
            set $key 1
        }
    }
    set nr_unresolved 0
    foreach unresolved_pair $unresolved_references {
        lassign $unresolved_pair page name parent_id
        set key _unsresolved_nodes($name,parent_id)
        if {![info exists $key]} {
            set $key u[incr nr_unresolved]
        }
        append nodes [subst {"[set $key]" \[label="$name", fontsize=$fontsize, shape=diamond, fontcolor=red, color=red\] \n}]
        append edges [subst {"n$page" -> "[set $key]"\n}]
    }
    set graph [subst {
        digraph D {
            rankdir=$rankdir; outputMode=edgesfirst;
            $nodes
            $edges
        }}]
    set css {
        div.xowiki-content .content-with-folders {
            float: left; width: 80%;
        }
        /*svg g a:link {text-decoration: none;}*/
        /*div.inner svg {width: 100%; height: 100%; margin: 0 auto;}*/
        svg g polygon {fill: transparent;}
        svg g g ellipse {fill: #eeeef4;}
        svg g g polygon {fill: #f4f4e4;}
    }
    
    #ns_log notice $graph
    set HTMLgraph [util::inline_svg_from_dot -css $css $graph]
    return "<div class='[namespace tail [self class]]'>$HTMLgraph</div>"