- Publicity: Public Only All
references-graph-procs.tcl
Includelet for a graph displaying wiki references.
- Location:
- packages/xowiki/tcl/references-graph-procs.tcl
- Author:
- Gustaf Neumann
Procedures in this file
Detailed information
[ hide source ] | [ make this the default ]Content File Source
::xo::library doc { Includelet for a graph displaying wiki references. @author Gustaf Neumann } ::xo::library require includelet-procs if {[info commands ::try] eq ""} { package require try } namespace eval ::xowiki::includelet { ::xowiki::IncludeletClass create references-graph \ -superclass ::xowiki::Includelet \ -parameter { {__decoration none} {parameter_declaration { {-folder .} {-page ""} {-link_type link} {-rankdir LR} {-fontsize 12} }} } -ad_doc { 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. @param page starting page for a partial link graph, provided as item ref @param folder starting page for showing all children of a folder (default .) @param rankdir possible values LR, TB, BT, or RL @param fontsize fontsize for graphviz (default 12) } references-graph instproc render {} { :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>" } } ::xo::library source_dependent # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: