From e83452e4a5f8b9a3eeb851095f28a73272650a7b Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Tue, 6 Nov 2012 13:26:57 -0500
Subject: [PATCH] Began work on collection module -- basic hierarchy display is
 now functional.

---
 config/vufind/HierarchyDefault.ini            |  17 ++
 config/vufind/HierarchyFlat.ini               |  17 ++
 config/vufind/config.ini                      |  10 +-
 module/VuFind/config/module.config.php        |  33 ++-
 module/VuFind/src/VuFind/Bootstrap.php        |   7 +-
 .../VuFind/Hierarchy/Driver/AbstractBase.php  | 172 +++++++++++++++
 .../Hierarchy/Driver/ConfigurationBased.php   | 127 +++++++++++
 .../src/VuFind/Hierarchy/Driver/Factory.php   |  73 +++++++
 .../VuFind/Hierarchy/Driver/PluginManager.php |  51 +++++
 .../Hierarchy/TreeDataSource/AbstractBase.php | 131 +++++++++++
 .../TreeDataSource/PluginManager.php          |  51 +++++
 .../VuFind/Hierarchy/TreeDataSource/Solr.php  | 204 ++++++++++++++++++
 .../Hierarchy/TreeDataSource/XMLFile.php      | 100 +++++++++
 .../Hierarchy/TreeRenderer/AbstractBase.php   | 147 +++++++++++++
 .../VuFind/Hierarchy/TreeRenderer/JSTree.php  | 183 ++++++++++++++++
 .../Hierarchy/TreeRenderer/PluginManager.php  |  51 +++++
 .../src/VuFind/RecordDriver/PluginManager.php |  16 ++
 .../src/VuFind/RecordDriver/SolrDefault.php   | 107 +++++++++
 .../src/VuFind/RecordTab/HierarchyTree.php    | 126 +++++++++++
 module/VuFind/xsl/Hierarchy/RecordList.xsl    |  30 +++
 solr/biblio/conf/schema.xml                   |   9 +
 themes/blueprint/css/styles.css               |  10 +-
 .../SolrDefault/result-list.phtml             |  11 +
 .../templates/RecordTab/hierarchytree.phtml   |  22 ++
 .../templates/RecordTab/hierarchytree.phtml   |  22 ++
 25 files changed, 1720 insertions(+), 7 deletions(-)
 create mode 100644 config/vufind/HierarchyDefault.ini
 create mode 100644 config/vufind/HierarchyFlat.ini
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/Driver/AbstractBase.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/Driver/ConfigurationBased.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/Driver/Factory.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/Driver/PluginManager.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/TreeDataSource/AbstractBase.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/TreeDataSource/PluginManager.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/TreeDataSource/Solr.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/TreeDataSource/XMLFile.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/TreeRenderer/AbstractBase.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/TreeRenderer/JSTree.php
 create mode 100644 module/VuFind/src/VuFind/Hierarchy/TreeRenderer/PluginManager.php
 create mode 100644 module/VuFind/src/VuFind/RecordTab/HierarchyTree.php
 create mode 100644 module/VuFind/xsl/Hierarchy/RecordList.xsl
 create mode 100644 themes/blueprint/templates/RecordTab/hierarchytree.phtml
 create mode 100644 themes/jquerymobile/templates/RecordTab/hierarchytree.phtml

diff --git a/config/vufind/HierarchyDefault.ini b/config/vufind/HierarchyDefault.ini
new file mode 100644
index 00000000000..833131f7c55
--- /dev/null
+++ b/config/vufind/HierarchyDefault.ini
@@ -0,0 +1,17 @@
+[HierarchyTree]
+; Are hierarchy trees visible? -- true or false (default false)
+show = true
+; The source of the hierarchy data -- may be Solr or XMLFile
+treeSource = Solr
+; When using Solr as a treeSource, this value determines how long tree data is
+; cached (in seconds) -- default 12h
+solrCacheTime = 43200
+; When using XMLFile as a treeSource, this value specifies where tree data is found
+;XMLFileDir = /usr/local/vufind/hierarchy_xml
+; Sorting requires the hierarchy_sequence field to be populated; defaults to false
+sorting = true
+; Which Tree Renderer to Use - Default is JSTree
+;treeRenderer = JSTree
+; Control whether or not to display the full hierarchy tree in record mode
+; (true = show full hierarchy, false = show partial hierarchy, default = true)
+fullHierarchyRecordView = true
diff --git a/config/vufind/HierarchyFlat.ini b/config/vufind/HierarchyFlat.ini
new file mode 100644
index 00000000000..e7696bcc02a
--- /dev/null
+++ b/config/vufind/HierarchyFlat.ini
@@ -0,0 +1,17 @@
+[HierarchyTree]
+; Are hierarchy trees visible? -- true or false (default false)
+show = false
+; The source of the hierarchy data -- may be Solr or XMLFile
+;treeSource = Solr
+; When using Solr as a treeSource, this value determines how long tree data is
+; cached (in seconds) -- default 12h
+;solrCacheTime = 0
+; When using XMLFile as a treeSource, this value specifies where tree data is found
+;XMLFileDir = /usr/local/vufind/hierarchy_xml
+; Sorting requires the hierarchy_sequence field to be populated; defaults to false
+;sorting = true
+; Which Tree Renderer to Use - Default is JSTree
+;treeRenderer = JSTree
+; Control whether or not to display the full hierarchy tree in record mode
+; (true = show full hierarchy, false = show partial hierarchy, default = true)
+fullHierarchyRecordView = true
diff --git a/config/vufind/config.ini b/config/vufind/config.ini
index 500568f5362..daa6b4d77ae 100644
--- a/config/vufind/config.ini
+++ b/config/vufind/config.ini
@@ -767,4 +767,12 @@ HMACkey = mySuperSecretValue
 ; Default dir_permission seems to be 0700.
 ;dir_permission = 0700
 ; Default file_permission seems to be 0600.
-;file_permission = 0600
\ No newline at end of file
+;file_permission = 0600
+
+; This section addresses hierarchical records in the Solr index
+[Hierarchy]
+; Name of hierarchy driver to use if no value is specified in the hierarchytype
+; field of the Solr index.
+driver = Default
+; Should we display hierarchy trees? (default = false)
+;showTree = true
\ No newline at end of file
diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index 267aae7b9b1..39ea5c2c216 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -174,6 +174,34 @@ $config = array(
             'userstatsfields' => 'VuFind\Db\Table\UserStatsFields',
         ),
     ),
+    'hierarchy_driver_plugin_manager' => array(
+        'factories' => array(
+            'default' => function ($sm) {
+                return \VuFind\Hierarchy\Driver\Factory::get($sm->getServiceLocator(), 'HierarchyDefault');
+            },
+            'flat' => function ($sm) {
+                return \VuFind\Hierarchy\Driver\Factory::get($sm->getServiceLocator(), 'HierarchyFlat');
+            },
+        )
+    ),
+    'hierarchy_treedatasource_plugin_manager' => array(
+        'factories' => array(
+            'solr' => function ($sm) {
+                $cacheDir = $sm->getServiceLocator()->get('VuFind\CacheManager')->getCacheDir();
+                return new \VuFind\Hierarchy\TreeDataSource\Solr(
+                    rtrim($cacheDir, '/') . '/hierarchy'
+                );
+            },
+        ),
+        'invokables' => array(
+            'xmlfile' => 'VuFind\Hierarchy\TreeDataSource\XMLFile',
+        ),
+    ),
+    'hierarchy_treerenderer_plugin_manager' => array(
+        'invokables' => array(
+            'jstree' => 'VuFind\Hierarchy\TreeRenderer\JSTree',
+        )
+    ),
     'ils_driver_plugin_manager' => array(
         'abstract_factories' => array('VuFind\ILS\Driver\PluginFactory'),
         'invokables' => array(
@@ -256,13 +284,13 @@ $config = array(
             'Holdings' => 'HoldingsILS', 'Description' => 'Description',
             'TOC' => 'TOC', 'UserComments' => 'UserComments',
             'Reviews' => 'Reviews', 'Excerpt' => 'Excerpt',
-            'Details' => 'StaffViewArray',
+            'HierarchyTree' => 'HierarchyTree', 'Details' => 'StaffViewArray',
         ),
         'VuFind\RecordDriver\SolrMarc' => array(
             'Holdings' => 'HoldingsILS', 'Description' => 'Description',
             'TOC' => 'TOC', 'UserComments' => 'UserComments',
             'Reviews' => 'Reviews', 'Excerpt' => 'Excerpt',
-            'Details' => 'StaffViewMARC',
+            'HierarchyTree' => 'HierarchyTree', 'Details' => 'StaffViewMARC',
         ),
         'VuFind\RecordDriver\Summon' => array(
             'Description' => 'Description',
@@ -282,6 +310,7 @@ $config = array(
         'invokables' => array(
             'description' => 'VuFind\RecordTab\Description',
             'excerpt' => 'VuFind\RecordTab\Excerpt',
+            'hierarchytree' => 'VuFind\RecordTab\HierarchyTree',
             'holdingsils' => 'VuFind\RecordTab\HoldingsILS',
             'holdingsworldcat' => 'VuFind\RecordTab\HoldingsWorldCat',
             'reviews' => 'VuFind\RecordTab\Reviews',
diff --git a/module/VuFind/src/VuFind/Bootstrap.php b/module/VuFind/src/VuFind/Bootstrap.php
index 2af408df0f1..95499d83776 100644
--- a/module/VuFind/src/VuFind/Bootstrap.php
+++ b/module/VuFind/src/VuFind/Bootstrap.php
@@ -88,9 +88,10 @@ class Bootstrap
 
         // Use naming conventions to set up a bunch of services based on namespace:
         $namespaces = array(
-            'Auth', 'Autocomplete', 'Db\Table', 'ILS\Driver', 'Recommend',
-            'RecordDriver', 'RecordTab', 'Related', 'Resolver\Driver', 'Session',
-            'Statistics\Driver'
+            'Auth', 'Autocomplete', 'Db\Table', 'Hierarchy\Driver',
+            'Hierarchy\TreeDataSource', 'Hierarchy\TreeRenderer', 'ILS\Driver',
+            'Recommend', 'RecordDriver', 'RecordTab', 'Related', 'Resolver\Driver',
+            'Session', 'Statistics\Driver'
         );
         foreach ($namespaces as $ns) {
             $serviceName = 'VuFind\\' . str_replace('\\', '', $ns) . 'PluginManager';
diff --git a/module/VuFind/src/VuFind/Hierarchy/Driver/AbstractBase.php b/module/VuFind/src/VuFind/Hierarchy/Driver/AbstractBase.php
new file mode 100644
index 00000000000..353f1d32ae3
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/Driver/AbstractBase.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ * Hierarchy interface.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Hierarchy
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_a_search_object Wiki
+ */
+namespace VuFind\Hierarchy\Driver;
+use VuFind\Hierarchy\TreeDataSource\PluginManager as DataManager,
+    VuFind\Hierarchy\TreeRenderer\PluginManager as RendererManager;
+
+/**
+ * Hierarchy interface class.
+ *
+ * Interface Hierarchy based drivers.
+ * This should be extended to implement functionality for specific
+ * Hierarchy Systems (i.e. Calm etc.).
+ *
+ * @category VuFind2
+ * @package  Hierarchy
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_a_search_object Wiki
+ */
+abstract class AbstractBase
+{
+    /**
+     * Driver configuration
+     *
+     * @var \Zend\Config\Config
+     */
+    protected $config;
+
+    /**
+     * Tree data source plugin manager
+     *
+     * @var DataManager
+     */
+    protected $dataManager;
+
+    /**
+     * Are trees globally enabled?
+     *
+     * @var bool
+     */
+    protected $enabled = true;
+
+    /**
+     * Tree renderer plugin manager
+     *
+     * @var RendererManager
+     */
+    protected $rendererManager;
+
+    /**
+     * Find out whether or not to show the tree
+     *
+     * @return bool
+     */
+    abstract public function showTree();
+
+    /**
+     * Constructor
+     *
+     * @param \Zend\Config\Config $config          Configuration
+     * @param DataManager         $dataManager     Tree data source plugin manager
+     * @param RendererManager     $rendererManager Tree renderer plugin manager
+     * @param array               $options         Extra options (if any)
+     */
+    public function __construct(\Zend\Config\Config $config,
+        DataManager $dataManager, RendererManager $rendererManager,
+        $options = array()
+    ) {
+        $this->config = $config;
+        $this->dataManager = $dataManager;
+        $this->rendererManager = $rendererManager;
+        if (isset($options['enabled'])) {
+            $this->enabled = (bool) $options['enabled'];
+        }
+    }
+
+    /**
+     * Returns the Source of the Tree
+     *
+     * @return object The tree data source object
+     */
+    public function getTreeSource()
+    {
+        $source = $this->dataManager->get($this->getTreeSourceType());
+        $source->setHierarchyDriver($this);
+        return $source;
+    }
+
+    /**
+     * Returns the actual object for generating trees
+     *
+     * @param \VuFind\RecordDriver\AbstractBase $driver Record driver
+     *
+     * @return object
+     */
+    public function getTreeRenderer(\VuFind\RecordDriver\AbstractBase $driver)
+    {
+        $renderer = $this->rendererManager->get($this->getTreeRendererType());
+        $renderer->setRecordDriver($driver);
+        return $renderer;
+    }
+
+    /**
+     * Render the tree for a given record.
+     *
+     * @param \VuFind\RecordDriver\AbstractBase $driver      Record driver
+     * @param string                            $context     Context in which the
+     * tree is being created
+     * @param string                            $mode        Type of tree required
+     * @param string                            $hierarchyID Hierarchy ID to get
+     * the tree for
+     *
+     * @return string
+     */
+    public function render(\VuFind\RecordDriver\AbstractBase $driver, $context,
+        $mode, $hierarchyID
+    ) {
+        if (!$this->showTree()) {
+            return false;
+        }
+        return $this->getTreeRenderer($driver)
+            ->render($context, $mode, $hierarchyID, $driver->getUniqueID());
+    }
+
+    /**
+     * Returns the Tree Renderer Type
+     *
+     * @return string
+     */
+    abstract public function getTreeRendererType();
+
+    /**
+     * Get Tree Settings
+     *
+     * Returns all the configuration settings for a hierarchy tree
+     *
+     * @return array The values of the configuration setting
+     */
+    abstract public function getTreeSettings();
+
+    /**
+     * Get Tree Data Source Type
+     *
+     * @return string
+     */
+    abstract public function getTreeSourceType();
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/Driver/ConfigurationBased.php b/module/VuFind/src/VuFind/Hierarchy/Driver/ConfigurationBased.php
new file mode 100644
index 00000000000..b7020e52a01
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/Driver/ConfigurationBased.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Configuration-Based Hierarchy Driver
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2007.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Hierarchy_Drivers
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_ils_driver Wiki
+ */
+namespace VuFind\Hierarchy\Driver;
+
+/**
+ * Configuration-Based Hierarchy Driver
+ *
+ * @category VuFind2
+ * @package  Hierarchy_Drivers
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_ils_driver Wiki
+ */
+class ConfigurationBased extends AbstractBase
+{
+    /**
+     * Default tree renderer
+     *
+     * @var string
+     */
+    protected $defaultTreeRenderer = 'JSTree';
+
+    /**
+     * Show Tree
+     *
+     * Returns the configuration setting for displaying a hierarchy tree
+     *
+     * @return bool The boolean value of the configuration setting
+     */
+    public function showTree()
+    {
+        $treeConfigDriver = isset($this->config->HierarchyTree->show)
+            ? $this->config->HierarchyTree->show : false;
+        return ($this->enabled && $treeConfigDriver);
+    }
+
+    /**
+     * Get Tree Renderer Type
+     *
+     * Returns the configuration setting for generating a hierarchy tree
+     *
+     * @return string The value of the configuration setting
+     */
+    public function getTreeRendererType()
+    {
+        return isset($this->config->HierarchyTree->treeRenderer)
+            ? $this->config->HierarchyTree->treeRenderer
+            : $this->defaultTreeRenderer;
+    }
+
+    /**
+     * Get Tree Data Source Type
+     *
+     * @return string
+     */
+    public function getTreeSourceType()
+    {
+        return isset($this->config->HierarchyTree->treeSource)
+            ? $this->config->HierarchyTree->treeSource
+            : 'Solr';
+    }
+
+    /**
+     * Get Tree Cache Time
+     *
+     * Returns the configuration setting for hierarchy tree caching time when
+     * using solr to build the tree
+     *
+     * @return int The value of the configuration setting
+     */
+    public function getTreeCacheTime()
+    {
+        return isset($this->config->HierarchyTree->solrCacheTime)
+            ? $this->config->HierarchyTree->solrCacheTime : 43200;
+    }
+
+    /**
+     * Check if sorting is enabled in the hierarchy Options
+     *
+     * Returns the configuration setting for hierarchy tree sorting
+     *
+     * @return bool The value of the configuration setting
+     */
+    public function treeSorting()
+    {
+        return isset($this->config->HierarchyTree->sorting)
+            ? $this->config->HierarchyTree->sorting : false;
+    }
+
+    /**
+     * Get Tree Settings
+     *
+     * Returns all the configuration settings for a hierarchy tree
+     *
+     * @return array The values of the configuration setting
+     */
+    public function getTreeSettings()
+    {
+        return isset($this->config->HierarchyTree)
+            ? $this->config->HierarchyTree->toArray() : array();
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/Driver/Factory.php b/module/VuFind/src/VuFind/Hierarchy/Driver/Factory.php
new file mode 100644
index 00000000000..9cf273e8747
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/Driver/Factory.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Hierarchy Factory Class
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Hierarchy_Drivers
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_a_search_object Wiki
+ */
+namespace VuFind\Hierarchy\Driver;
+
+/**
+ * Hierarchy Factory Class
+ *
+ * This is a factory class to build objects for managing hierarchies.
+ *
+ * @category VuFind2
+ * @package  Hierarchy_Drivers
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_a_search_object Wiki
+ */
+class Factory
+{
+    /**
+     * This constructs a hierarchy driver using VuFind's service setup.
+     *
+     * @param \Zend\ServiceManager\ServiceManager $sm     Service manager
+     * @param string                              $config Name of config to load
+     * @param string                              $class  Name of driver class
+     *
+     * @return object
+     */
+    public static function get(\Zend\ServiceManager\ServiceManager $sm, $config,
+        $class = 'VuFind\Hierarchy\Driver\ConfigurationBased'
+    ) {
+        // Set up options based on global VuFind settings:
+        $globalConfig = \VuFind\Config\Reader::getConfig();
+        $options = array(
+            'enabled' => isset($globalConfig->Hierarchy->showTree)
+                ? $globalConfig->Hierarchy->showTree : false
+        );
+
+        // Load driver-specific configuration:
+        $driverConfig = \VuFind\Config\Reader::getConfig($config);
+
+        // Build object:
+        return new $class(
+            $driverConfig,
+            $sm->get('VuFind\HierarchyTreeDataSourcePluginManager'),
+            $sm->get('VuFind\HierarchyTreeRendererPluginManager'),
+            $options
+        );
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/Driver/PluginManager.php b/module/VuFind/src/VuFind/Hierarchy/Driver/PluginManager.php
new file mode 100644
index 00000000000..5dfda51ca92
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/Driver/PluginManager.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Hierarchy driver plugin manager
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Hierarchy_Drivers
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+namespace VuFind\Hierarchy\Driver;
+
+/**
+ * Hierarchy driver plugin manager
+ *
+ * @category VuFind2
+ * @package  Hierarchy_Drivers
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
+{
+    /**
+     * Return the name of the base class or interface that plug-ins must conform
+     * to.
+     *
+     * @return string
+     */
+    protected function getExpectedInterface()
+    {
+        return 'VuFind\Hierarchy\Driver\AbstractBase';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/AbstractBase.php b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/AbstractBase.php
new file mode 100644
index 00000000000..f8861c76ae9
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/AbstractBase.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Hierarchy Tree Data Source (abstract base)
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+namespace VuFind\Hierarchy\TreeDataSource;
+use Zend\Log\LoggerInterface;
+
+/**
+ * Hierarchy Tree Data Source (abstract base)
+ *
+ * This is a base helper class for producing hierarchy Trees.
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+abstract class AbstractBase implements \Zend\Log\LoggerAwareInterface
+{
+    /**
+     * Logger object for debug info (or false for no debugging).
+     *
+     * @var LoggerInterface|bool
+     */
+    protected $logger = false;
+
+    /**
+     * Hierarchy driver
+     *
+     * @var \VuFind\Hierarchy\Driver\AbstractBase
+     */
+    protected $hierarchyDriver = null;
+
+    /**
+     * Set the logger
+     *
+     * @param LoggerInterface $logger Logger to use.
+     *
+     * @return void
+     */
+    public function setLogger(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
+    }
+
+    /**
+     * Output a debug message, if appropriate
+     *
+     * @param string $msg Message to display
+     *
+     * @return void
+     * @access protected
+     */
+    protected function debug($msg)
+    {
+        if ($this->logger) {
+            $this->logger->debug($msg);
+        }
+    }
+
+    /**
+     * Get the hierarchy driver
+     *
+     * @return \VuFind\Hierarchy\Driver\AbstractBase
+     * @throws \Exception
+     */
+    protected function getHierarchyDriver()
+    {
+        if (null === $this->hierarchyDriver) {
+            throw new \Exception('Missing hierarchy driver');
+        }
+        return $this->hierarchyDriver;
+    }
+
+    /**
+     * Set the hierarchy driver
+     *
+     * @param \VuFind\Hierarchy\Driver\AbstractBase $driver Hierarchy driver
+     *
+     * @return AbstractBase
+     */
+    public function setHierarchyDriver(\VuFind\Hierarchy\Driver\AbstractBase $driver)
+    {
+        $this->hierarchyDriver = $driver;
+        return $this;
+    }
+
+    /**
+     * Get XML for the specified hierarchy ID.
+     *
+     * @param string $id Hierarchy ID.
+     *
+     * @return string
+     */
+    abstract public function getXML($id);
+
+    /**
+     * Does this data source support the specified hierarchy ID?
+     *
+     * @param string $id Hierarchy ID.
+     *
+     * @return bool
+     */
+    abstract public function supports($id);
+}
+
+?>
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/PluginManager.php b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/PluginManager.php
new file mode 100644
index 00000000000..f3a6b4cd028
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/PluginManager.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Hierarchy tree data source plugin manager
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+namespace VuFind\Hierarchy\TreeDataSource;
+
+/**
+ * Hierarchy tree data source plugin manager
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
+{
+    /**
+     * Return the name of the base class or interface that plug-ins must conform
+     * to.
+     *
+     * @return string
+     */
+    protected function getExpectedInterface()
+    {
+        return 'VuFind\Hierarchy\TreeDataSource\AbstractBase';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/Solr.php b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/Solr.php
new file mode 100644
index 00000000000..3d6a01ca566
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/Solr.php
@@ -0,0 +1,204 @@
+<?php
+/**
+ * Hierarchy Tree Data Source (Solr)
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+namespace VuFind\Hierarchy\TreeDataSource;
+use VuFind\Connection\Manager as ConnectionManager;
+
+/**
+ * Hierarchy Tree Data Source (Solr)
+ *
+ * This is a base helper class for producing hierarchy Trees.
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+class Solr extends AbstractBase
+{
+    /**
+     * Solr connection
+     *
+     * @var object
+     */
+    protected $db;
+
+    /**
+     * Cache directory
+     *
+     * @var string
+     */
+    protected $cacheDir;
+
+    /**
+     * Constructor.
+     *
+     * @param string $cacheDir Directory to use for caching results (optional)
+     */
+    public function __construct($cacheDir = null)
+    {
+        $this->db = ConnectionManager::connectToIndex();
+        $this->cacheDir = rtrim($cacheDir, '/');
+    }
+
+    /**
+     * Get XML for the specified hierarchy ID.
+     *
+     * Build the XML file from the Solr fields
+     *
+     * TODO: this should return false if it fails.
+     *
+     * @param string $id Hierarchy ID.
+     *
+     * @return string
+     */
+    public function getXML($id)
+    {
+        $top = $this->db->getRecord($id);
+        $cacheFile = (null !== $this->cacheDir)
+            ? $this->cacheDir . '/hierarchyTree_' . urlencode($id) . '.xml'
+            : false;
+
+        $cacheTime = $this->getHierarchyDriver()->getTreeCacheTime();
+
+        if ($cacheFile && file_exists($cacheFile)
+            && filemtime($cacheFile) > (time() - $cacheTime)
+        ) {
+            $this->debug("Using cached data from $cacheFile");
+            $xml = file_get_contents($cacheFile);
+        } else {
+            $starttime = microtime(true);
+            $xml = '<root><item id="' .
+                htmlspecialchars($id) .
+                '">' .
+                '<content><name>' . htmlspecialchars($top['title']) .
+                '</name></content>';
+            $count = 0;
+            $xml .= $this->getChildren($id, $count);
+            $xml .= '</item></root>';
+            if ($cacheFile) {
+                if (!file_exists($this->cacheDir)) {
+                    mkdir($this->cacheDir);
+                }
+                file_put_contents($cacheFile, $xml);
+            }
+            $this->debug(
+                "Hierarchy of $count records built in " .
+                abs(microtime(true) - $starttime)
+            );
+        }
+        return $xml;
+    }
+
+    /**
+     * Get Solr Children
+     *
+     * @param string $parentID The starting point for the current recursion
+     * (equivlent to Solr field hierarchy_parent_id)
+     * @param string $count    The total count of items in the tree
+     * before this recursion
+     *
+     * @return string
+     */
+    protected function getChildren($parentID, &$count)
+    {
+        $query = 'hierarchy_parent_id:"' . addcslashes($parentID, '"') . '"';
+        $results = $this->db->search(array('query' => $query, 'limit' => 10000));
+        if ($results === false) {
+            return '';
+        }
+        $xml = array();
+        $sorting = $this->getHierarchyDriver()->treeSorting();
+
+        foreach ($results['response']['docs'] as $doc) {
+            ++$count;
+            if ($sorting) {
+                foreach ($doc['hierarchy_parent_id'] as $key => $val) {
+                    if ($val == $parentID) {
+                        $sequence = $doc['hierarchy_sequence'][$key];
+                    }
+                }
+            }
+
+            $this->debug("$parentID: " . $doc['id']);
+            $xmlNode = '';
+            $xmlNode .= '<item id="' . htmlspecialchars($doc['id']) .
+                '"><content><name>' .
+                htmlspecialchars($doc['title_full']) . '</name></content>';
+            $xmlNode .= $this->getChildren($doc['id'], $count);
+            $xmlNode .= '</item>';
+            array_push($xml, array((isset($sequence)?$sequence: 0),$xmlNode));
+        }
+
+        if ($sorting) {
+            $this->sortNodes($xml, 0);
+        }
+
+        $xmlReturnString = '';
+        foreach ($xml as $node) {
+            $xmlReturnString .= $node[1];
+        }
+        return $xmlReturnString;
+    }
+
+    /**
+     * Sort Nodes
+     *
+     * @param array  &$array The Array to Sort
+     * @param string $key    The key to sort on
+     *
+     * @return void
+     */
+    protected function sortNodes(&$array, $key)
+    {
+        $sorter=array();
+        $ret=array();
+        reset($array);
+        foreach ($array as $ii => $va) {
+            $sorter[$ii]=$va[$key];
+        }
+        asort($sorter);
+        foreach ($sorter as $ii => $va) {
+            $ret[$ii]=$array[$ii];
+        }
+        $array=$ret;
+    }
+
+    /**
+     * Does this data source support the specified hierarchy ID?
+     *
+     * @param string $id Hierarchy ID.
+     *
+     * @return bool
+     */
+    public function supports($id)
+    {
+        // Assume all IDs are supported.
+        return true;
+    }
+}
diff --git a/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/XMLFile.php b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/XMLFile.php
new file mode 100644
index 00000000000..1d883899f47
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/TreeDataSource/XMLFile.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Hierarchy Tree Data Source (XML File)
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+namespace VuFind\Hierarchy\TreeDataSource;
+
+/**
+ * Hierarchy Tree Data Source (XML File)
+ *
+ * This is a base helper class for producing hierarchy Trees.
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_DataSource
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+class XMLFile extends AbstractBase
+{
+    /**
+     * Base path to XML files
+     *
+     * @var string
+     */
+    protected $basePath = null;
+
+    /**
+     * Get the base path for XML files.
+     *
+     * @return string
+     */
+    protected function getBasePath()
+    {
+        if (null === $this->basePath) {
+            $settings = $this->getHierarchyDriver()->getTreeSettings();
+            $this->basePath = isset($settings['XMLFileDir'])
+                ? $settings['XMLFileDir'] : '';
+        }
+        return $this->basePath;
+    }
+
+    /**
+     * Get the full filename for the XML file for a specific ID.
+     *
+     * @param string $id Hierarchy ID.
+     *
+     * @return string
+     */
+    protected function getFilename($id)
+    {
+        return $this->getBasePath() . '/' . $id . '.xml';
+    }
+
+    /**
+     * Get XML for the specified hierarchy ID.
+     *
+     * @param string $id Hierarchy ID.
+     *
+     * @return string
+     */
+    public function getXML($id)
+    {
+        return file_get_contents($this->getFilename($id));
+    }
+
+    /**
+     * Does this data source support the specified hierarchy ID?
+     *
+     * @param string $id Hierarchy ID.
+     *
+     * @return bool
+     */
+    public function supports($id)
+    {
+        return file_exists($this->getFilename($id));
+    }
+}
diff --git a/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/AbstractBase.php b/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/AbstractBase.php
new file mode 100644
index 00000000000..0a6e5027168
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/AbstractBase.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Hierarchy Tree Renderer
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_Renderer
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+namespace VuFind\Hierarchy\TreeRenderer;
+
+/**
+ * Hierarchy Tree Renderer
+ *
+ * This is a base helper class for producing hierarchy Trees.
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_Renderer
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+abstract class AbstractBase
+{
+    /**
+     * Hierarchical record to work on
+     *
+     * @var \VuFind\RecordDriver\AbstractBase
+     */
+    protected $recordDriver = null;
+
+    /**
+     * Source of hierarchy data
+     *
+     * @var \VuFind\Hierarchy\TreeDataSource\AbstractBase
+     */
+    protected $dataSource = null;
+
+    /**
+     * Set the record driver to operate on
+     *
+     * @param \VuFind\RecordDriver\AbstractBase $driver Record driver
+     *
+     * @return AbstractBase
+     */
+    public function setRecordDriver(\VuFind\RecordDriver\AbstractBase $driver)
+    {
+        $this->recordDriver = $driver;
+        return $this;
+    }
+
+    /**
+     * Get the current record driver
+     *
+     * @return \VuFind\RecordDriver\AbstractBase
+     * @throws \Exception
+     */
+    protected function getRecordDriver()
+    {
+        if (null === $this->recordDriver) {
+            throw new \Exception('Missing record driver object');
+        }
+        return $this->recordDriver;
+    }
+
+    /**
+     * Get the current hierarchy data source
+     *
+     * @return \VuFind\Hierarchy\TreeDataSource\AbstractBase
+     * @throws \Exception
+     */
+    protected function getDataSource()
+    {
+        if (null === $this->dataSource) {
+            // Load the hierarchy driver from the record driver -- throw exception if
+            // this fails, since we shouldn't be using this class for drivers that do
+            // not support hierarchies!
+            $hierarchyDriver = $this->getRecordDriver()
+                ->tryMethod('getHierarchyDriver');
+            if (!is_object($hierarchyDriver)) {
+                throw new \Exception('Cannot load hierarchy driver from record driver.');
+            }
+            $this->dataSource = $hierarchyDriver->getTreeSource();
+        }
+        return $this->dataSource;
+    }
+
+    /**
+     * Get a list of trees containing the item represented by the stored record
+     * driver.
+     *
+     * @param string $hierarchyID Optional filter: specific hierarchy ID to retrieve
+     *
+     * @return mixed An array of hierarchy IDS if an archive tree exists,
+     * false if it does not
+     */
+    abstract public function getTreeList($hierarchyID = false);
+
+    /**
+     * Render the Hierarchy Tree
+     *
+     * @param string $context     The context from which the call has been made
+     * @param string $mode        The mode in which the tree should be generated
+     * @param string $hierarchyID The hierarchy ID of the tree to fetch (optional)
+     * @param string $recordID    The current record ID (optional)
+     *
+     * @return mixed The desired hierarchy tree output (or false on error)
+     */
+    abstract public function render(
+        $context, $mode, $hierarchyID, $recordID = false
+    );
+
+    /**
+     * Get Hierarchy Name
+     *
+     * @param string $hierarchyID        The hierarchy ID to find the title for
+     * @param string $inHierarchies      An array of hierarchy IDs
+     * @param string $inHierarchiesTitle An array of hierarchy Titles
+     *
+     * @return string A hierarchy title
+     */
+    public function getHierarchyName(
+        $hierarchyID, $inHierarchies, $inHierarchiesTitle
+    ) {
+        $keys = array_flip($inHierarchies);
+        $key = $keys[$hierarchyID];
+        return $inHierarchiesTitle[$key];
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/JSTree.php b/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/JSTree.php
new file mode 100644
index 00000000000..476b2ef7d37
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/JSTree.php
@@ -0,0 +1,183 @@
+<?php
+/**
+ * Hierarchy Tree Renderer for the JS_Tree plugin
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_Renderer
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+namespace VuFind\Hierarchy\TreeRenderer;
+
+/**
+ * Hierarchy Tree Renderer
+ *
+ * This is a helper class for producing hierarchy trees.
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_Renderer
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/building_an_authentication_handler Wiki
+ */
+
+class JSTree extends AbstractBase
+    implements \VuFind\I18n\Translator\TranslatorAwareInterface
+{
+    /**
+     * Translator (or null if unavailable)
+     *
+     * @var \Zend\I18n\Translator\Translator
+     */
+    protected $translator = null;
+
+    /**
+     * Set a translator
+     *
+     * @param \Zend\I18n\Translator\Translator $translator Translator
+     *
+     * @return AbstractBase
+     */
+    public function setTranslator(\Zend\I18n\Translator\Translator $translator)
+    {
+        $this->translator = $translator;
+        return $this;
+    }
+
+    /**
+     * Translate a string if a translator is available.
+     *
+     * @param string $msg Message to translate
+     *
+     * @return string
+     */
+    public function translate($msg)
+    {
+        return null !== $this->translator
+            ? $this->translator->translate($msg) : $msg;
+    }
+
+    /**
+     * Get a list of trees containing the item represented by the stored record
+     * driver.
+     *
+     * @param string $hierarchyID Optional filter: specific hierarchy ID to retrieve
+     *
+     * @return mixed An array of hierarchy IDS if an archive tree exists,
+     * false if it does not
+     */
+    public function getTreeList($hierarchyID = false)
+    {
+        $record = $this->getRecordDriver();
+        $id = $record->getUniqueID();
+        $inHierarchies = $record->getHierarchyTopID();
+        $inHierarchiesTitle = $record->getHierarchyTopTitle();
+
+        if ($hierarchyID) {
+            // Specific Hierarchy Supplied
+            if (in_array($hierarchyID, $inHierarchies)
+                && $this->getDataSource()->supports($hierarchyID)
+            ) {
+                return array(
+                    $hierarchyID => $this->getHierarchyName(
+                        $hierarchyID, $inHierarchies, $inHierarchiesTitle
+                    )
+                );
+            }
+        } else {
+            // Return All Hierarchies
+            $i = 0;
+            $hierarchies = array();
+            foreach ($inHierarchies as $hierarchyTopID) {
+                if ($this->getDataSource()->supports($hierarchyTopID)) {
+                    $hierarchies[$hierarchyTopID] = $inHierarchiesTitle[$i];
+                }
+                $i++;
+            }
+            if (!empty($hierarchies)) {
+                return $hierarchies;
+            }
+        }
+
+        // If we got this far, we couldn't find valid match(es).
+        return false;
+    }
+
+    /**
+     * Render the Hierarchy Tree
+     *
+     * @param string $context     The context from which the call has been made
+     * @param string $mode        The mode in which the tree should be generated
+     * @param string $hierarchyID The hierarchy ID of the tree to fetch (optional)
+     * @param string $recordID    The current record ID (optional)
+     *
+     * @return mixed The desired hierarchy tree output (or false on error)
+     */
+    public function render($context, $mode, $hierarchyID, $recordID = false)
+    {
+        if (!empty($context) && !empty($mode)) {
+            return $this->transformCollectionXML(
+                $context, $mode, $hierarchyID, $recordID
+            );
+        }
+        return false;
+    }
+
+    /**
+     * transformCollectionXML
+     *
+     * Transforms Collection XML to Desired Format
+     *
+     * @param string $context     The Context in which the tree is being displayed
+     * @param string $mode        The Mode in which the tree is being displayed
+     * @param string $hierarchyID The hierarchy to get the tree for
+     * @param string $recordID    The currently selected Record (false for none)
+     *
+     * @return string A HTML List
+     */
+    protected function transformCollectionXML(
+        $context, $mode, $hierarchyID, $recordID
+    ) {
+        $record = $this->getRecordDriver();
+        $inHierarchies = $record->getHierarchyTopID();
+        $inHierarchiesTitle = $record->getHierarchyTopTitle();
+
+        $hierarchyTitle = $this->getHierarchyName(
+            $hierarchyID, $inHierarchies, $inHierarchiesTitle
+        );
+
+        // Set up parameters for XSL transformation
+        $params = array(
+            'titleText' => $this->translate('collection_view_record'),
+            'collectionID' => $hierarchyID,
+            'collectionTitle' => $hierarchyTitle,
+            'baseURL' => '%%%%VUFIND-BASE-URL%%%%',
+            'context' => $context,
+            'recordID' => $recordID
+        );
+
+        // Transform the XML
+        $xmlFile = $this->getDataSource()->getXML($hierarchyID);
+        $transformation = ucfirst($context) . ucfirst($mode);
+        $xslFile = "Hierarchy/{$transformation}.xsl";
+        return \VuFind\XSLT\Processor::process($xslFile, $xmlFile, $params);
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/PluginManager.php b/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/PluginManager.php
new file mode 100644
index 00000000000..9499a2927ec
--- /dev/null
+++ b/module/VuFind/src/VuFind/Hierarchy/TreeRenderer/PluginManager.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Hierarchy tree renderer plugin manager
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_Renderer
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+namespace VuFind\Hierarchy\TreeRenderer;
+
+/**
+ * Hierarchy tree renderer plugin manager
+ *
+ * @category VuFind2
+ * @package  HierarchyTree_Renderer
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
+{
+    /**
+     * Return the name of the base class or interface that plug-ins must conform
+     * to.
+     *
+     * @return string
+     */
+    protected function getExpectedInterface()
+    {
+        return 'VuFind\Hierarchy\TreeRenderer\AbstractBase';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/RecordDriver/PluginManager.php b/module/VuFind/src/VuFind/RecordDriver/PluginManager.php
index 4f1f901a0ed..97896b779ef 100644
--- a/module/VuFind/src/VuFind/RecordDriver/PluginManager.php
+++ b/module/VuFind/src/VuFind/RecordDriver/PluginManager.php
@@ -48,6 +48,22 @@ class PluginManager extends \VuFind\ServiceManager\AbstractPluginManager
     ) {
         parent::__construct($configuration);
 
+        // Add an initializer for setting up hierarchies
+        $initializer = function ($instance, $manager) {
+            $hasHierarchyType = is_callable(array($instance, 'getHierarchyType'));
+            if ($hasHierarchyType
+                && is_callable(array($instance, 'setHierarchyDriverManager'))
+            ) {
+                $sm = $manager->getServiceLocator();
+                if ($sm->has('VuFind\HierarchyDriverPluginManager')) {
+                    $instance->setHierarchyDriverManager(
+                        $sm->get('VuFind\HierarchyDriverPluginManager')
+                    );
+                }
+            }
+        };
+        $this->addInitializer($initializer, false);
+
         // Record drivers are not meant to be shared -- every time we retrieve one,
         // we are building a brand new object.
         $this->setShareByDefault(false);
diff --git a/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php b/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php
index b159d3db2f5..1b74ae5cbc0 100644
--- a/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php
+++ b/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php
@@ -89,6 +89,20 @@ class SolrDefault extends AbstractBase
      */
     protected $snippet = false;
 
+    /**
+     * Hierarchy driver plugin manager
+     *
+     * @var \VuFind\Hierarchy\Driver\PluginManager
+     */
+    protected $hierarchyDriverManager = null;
+
+    /**
+     * Hierarchy driver for current object
+     *
+     * @var \VuFind\Hierarchy\Driver\AbstractBase
+     */
+    protected $hierarchyDriver = null;
+
     /**
      * Constructor.
      */
@@ -1030,6 +1044,99 @@ class SolrDefault extends AbstractBase
         return array();
     }
 
+    /**
+     * Get a hierarchy driver appropriate to the current object.  (May be false if
+     * disabled/unavailable).
+     *
+     * @return \VuFind\Hierarchy\Driver\AbstractBase|bool
+     */
+    public function getHierarchyDriver()
+    {
+        if (null === $this->hierarchyDriver
+            && null !== $this->hierarchyDriverManager
+        ) {
+            $type = $this->getHierarchyType();
+            $this->hierarchyDriver = $type
+                ? $this->hierarchyDriverManager->get($type) : false;
+        }
+        return $this->hierarchyDriver;
+    }
+
+    /**
+     * Inject a hierarchy driver plugin manager.
+     *
+     * @param \VuFind\Hierarchy\Driver\PluginManager $pm Hierarchy driver manager
+     *
+     * @return SolrDefault
+     */
+    public function setHierarchyDriverManager(
+        \VuFind\Hierarchy\Driver\PluginManager $pm
+    ) {
+        $this->hierarchyDriverManager = $pm;
+        return $this;
+    }
+
+    /**
+     * Get the hierarchy_top_id(s) associated with this item (empty if none).
+     *
+     * @return array
+     */
+    public function getHierarchyTopID()
+    {
+        return isset($this->fields['hierarchy_top_id'])
+            ? $this->fields['hierarchy_top_id'] : array();
+    }
+
+    /**
+     * Get the absolute parent title(s) associated with this item
+     * (empty if none).
+     *
+     * @return array
+     */
+    public function getHierarchyTopTitle()
+    {
+        return isset($this->fields['hierarchy_top_title'])
+            ? $this->fields['hierarchy_top_title'] : array();
+    }
+
+    /**
+     * Get a list of hierarchy trees containing this record.
+     *
+     * @param string $hierarchyID The hierarchy to get the tree for
+     *
+     * @return mixed An associative array of hierachy trees on success (id => title),
+     * false if no hierarchies found
+     */
+    public function getHierarchyTrees($hierarchyID = false)
+    {
+        $hierarchyDriver = $this->getHierarchyDriver();
+        if ($hierarchyDriver && $hierarchyDriver->showTree()) {
+            return $hierarchyDriver->getTreeRenderer($this)
+                ->getTreeList($hierarchyID);
+        }
+        return false;
+    }
+
+    /**
+     * Get the Hierarchy Type (false if none)
+     *
+     * @return string|bool
+     */
+    public function getHierarchyType()
+    {
+        if (isset($this->fields['hierarchy_top_id'])) {
+            $hierarchyType = isset($this->fields['hierarchytype'])
+                ? $this->fields['hierarchytype'] : false;
+            if (!$hierarchyType) {
+                $config = ConfigReader::getConfig();
+                $hierarchyType = isset($config->Hierarchy->driver)
+                    ? $config->Hierarchy->driver : false;
+            }
+            return $hierarchyType;
+        }
+        return false;
+    }
+
     /**
      * Return the unique identifier of this record within the Solr index;
      * useful for retrieving additional information (like tags and user
diff --git a/module/VuFind/src/VuFind/RecordTab/HierarchyTree.php b/module/VuFind/src/VuFind/RecordTab/HierarchyTree.php
new file mode 100644
index 00000000000..060fccd29e1
--- /dev/null
+++ b/module/VuFind/src/VuFind/RecordTab/HierarchyTree.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * HierarchyTree tab
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  RecordTabs
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+namespace VuFind\RecordTab;
+use VuFind\Config\Reader as ConfigReader;
+
+/**
+ * HierarchyTree tab
+ *
+ * @category VuFind2
+ * @package  RecordTabs
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/creating_a_session_handler Wiki
+ */
+class HierarchyTree extends AbstractBase
+{
+    /**
+     * Tree data
+     *
+     * @var array
+     */
+    protected $treeList = null;
+
+    /**
+     * Get the on-screen description for this tab.
+     *
+     * @return string
+     */
+    public function getDescription()
+    {
+        return 'hierarchy_tree';
+    }
+
+    /**
+     * Is this tab active?
+     *
+     * @return bool
+     */
+    public function isActive()
+    {
+        $trees = $this->getTreeList();
+        return !empty($trees);
+    }
+
+    /**
+     * Get the ID of the active tree (false if none)
+     *
+     * @return string|bool
+     */
+    public function getActiveTree()
+    {
+        $treeList = $this->getTreeList();
+        if (count($treeList) == 1) {
+            $keys = array_keys($treeList);
+            return $keys[0];
+        } else {
+            return ($request = $this->getRequest())
+                ? $request->getQuery('hierarchy', false)
+                : false;
+        }
+    }
+
+    /**
+     * Get an array of tree data
+     *
+     * @return array
+     */
+    public function getTreeList()
+    {
+        if (null === $this->treeList) {
+            $this->treeList
+                = $this->getRecordDriver()->tryMethod('getHierarchyTrees');
+            if (null === $this->treeList) {
+                $this->treeList = array();
+            }
+        }
+        return $this->treeList;
+    }
+
+    /**
+     * Render a hierarchy tree
+     *
+     * @param string $baseUrl Base URL to use in links within tree
+     * @param string $id      Hierarchy ID (omit to use active tree)
+     *
+     * @return string
+     */
+    public function renderTree($baseUrl, $id = null)
+    {
+        $id = (null === $id) ? $this->getActiveTree() : $id;
+        $recordDriver = $this->getRecordDriver();
+        $hierarchyDriver = $recordDriver->tryMethod('getHierarchyDriver');
+        if (is_object($hierarchyDriver)) {
+            $tree = $hierarchyDriver->render($recordDriver, 'Record', 'List', $id);
+            return str_replace(
+                '%%%%VUFIND-BASE-URL%%%%', rtrim($baseUrl, '/'), $tree
+            );
+        }
+        return '';
+    }
+}
\ No newline at end of file
diff --git a/module/VuFind/xsl/Hierarchy/RecordList.xsl b/module/VuFind/xsl/Hierarchy/RecordList.xsl
new file mode 100644
index 00000000000..71aa6969c06
--- /dev/null
+++ b/module/VuFind/xsl/Hierarchy/RecordList.xsl
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
+
+    <xsl:template match="/">
+        <div id="treeList">
+        <xsl:apply-templates select="//root">
+        </xsl:apply-templates>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="item">
+        <ul>
+          <xsl:variable name="id" select="@id" />
+          <li>
+          <xsl:attribute name="id">tree-<xsl:value-of select="$id"/></xsl:attribute>
+          <xsl:attribute name="class">
+          <xsl:choose>
+            <xsl:when test="$recordID = $id">currentRecord</xsl:when>
+          </xsl:choose>
+          </xsl:attribute>
+        <xsl:variable name="baseModule">Record</xsl:variable>
+          <a href="{$baseURL}/{$baseModule}/{$id}/HierarchyTree?hierarchy={$collectionID}&amp;recordID={$id}#tree-{$id}" title="{$titleText}">
+              <xsl:value-of select="./content/name" />
+          </a>
+          <xsl:apply-templates select="item"/>
+      </li>
+      </ul>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/solr/biblio/conf/schema.xml b/solr/biblio/conf/schema.xml
index 5b786c38462..e7ec375b603 100644
--- a/solr/biblio/conf/schema.xml
+++ b/solr/biblio/conf/schema.xml
@@ -176,6 +176,15 @@
    <field name="container_issue" type="text" indexed="true" stored="true"/>
    <field name="container_start_page" type="text" indexed="true" stored="true"/>
    <field name="container_reference" type="text" indexed="true" stored="true"/>
+   <!-- Hierarchy Fields -->
+   <field name="hierarchytype" type="string" index="true" stored="true" multiValued="false"/>
+   <field name="hierarchy_top_id" type="string" index="true" stored="true" multiValued="true"/>
+   <field name="hierarchy_top_title" type="string" index="true" stored="true" multiValued="true"/>
+   <field name="hierarchy_parent_id" type="string" indexed="true" stored="true" multiValued="true"/>
+   <field name="hierarchy_parent_title" type="string" indexed="true" stored="true" multiValued="true"/>
+   <field name="hierarchy_sequence" type="string" indexed="true" stored="true" multiValued="true"/>
+   <field name="is_hierarchy_id" type="string" indexed="true" stored="true" multiValued="false"/>
+   <field name="is_hierarchy_title" type="string" indexed="true" stored="true" multiValued="false"/>
    <!-- Used for loading correct record driver -->
    <field name="recordtype" type="string" indexed="false" stored="true"/>
    <!-- Tracking fields to keep track of oldest and most recent index times -->
diff --git a/themes/blueprint/css/styles.css b/themes/blueprint/css/styles.css
index fa7a0b79493..d97a5f6ebc9 100644
--- a/themes/blueprint/css/styles.css
+++ b/themes/blueprint/css/styles.css
@@ -1735,4 +1735,12 @@ div#closeContextHelp:active {
 /* Make sure COinS information is invisible */
 .Z3988 {
     display: none;
-}
\ No newline at end of file
+}
+
+.currentTree, .hierarchyTreeLinkText {
+    background-image:url(../images/fugue/treeCurrent.png);
+    background-repeat:no-repeat;
+    background-position: left;
+    padding:.5em .5em .5em 20px;
+    margin-right:1em;
+}
diff --git a/themes/blueprint/templates/RecordDriver/SolrDefault/result-list.phtml b/themes/blueprint/templates/RecordDriver/SolrDefault/result-list.phtml
index efb9e2cbfab..601825ececa 100644
--- a/themes/blueprint/templates/RecordDriver/SolrDefault/result-list.phtml
+++ b/themes/blueprint/templates/RecordDriver/SolrDefault/result-list.phtml
@@ -107,6 +107,17 @@
     <div class="savedLists info hide">
       <strong><?=$this->transEsc("Saved in")?>:</strong>
     </div>
+
+    <? $trees = $this->driver->tryMethod('getHierarchyTrees'); if (!empty($trees)): ?>
+      <? foreach ($trees as $hierarchyID => $hierarchyTitle): ?>
+        <div class="hierarchyTreeLink">
+          <input type="hidden" value="<?=$this->escapeHtml($hierarchyID)?>" class="hiddenHierarchyId" />
+          <a class="hierarchyTreeLinkText" href="<?=$this->recordLink()->getTabUrl($this->driver, 'HierarchyTree')?>?hierarchy=<?=urlencode($hierarchyID)?>#tabnav" title="<?=$this->transEsc('hierarchy_tree')?>">
+            <?=$this->transEsc('hierarchy_view_context')?><? if (count($trees) > 1): ?>: <?=$this->escapeHtml($hierarchyTitle)?><? endif; ?>
+          </a>
+        </div>
+      <? endforeach; ?>
+    <? endif; ?>
   </div>
 
   <div class="clear"></div>
diff --git a/themes/blueprint/templates/RecordTab/hierarchytree.phtml b/themes/blueprint/templates/RecordTab/hierarchytree.phtml
new file mode 100644
index 00000000000..656aaf248f6
--- /dev/null
+++ b/themes/blueprint/templates/RecordTab/hierarchytree.phtml
@@ -0,0 +1,22 @@
+<?
+    // Set page title.
+    $this->headTitle($this->translate('hierarchy_tree') . ': ' . $this->driver->getBreadcrumb());
+    $hierarchyTreeList = $this->tab->getTreeList();
+    $activeTree = $this->tab->getActiveTree();
+?>
+<div>
+  <? if (count($hierarchyTreeList) > 1): ?>
+    <div id="treeSelector">
+      <? foreach ($hierarchyTreeList as $hierarchy => $hierarchyTitle): ?>
+        <a class="tree<?=($activeTree == $hierarchy) ? ' currentTree' : ''?>" href="<?=$this->recordLink()->getTabUrl($this->driver, 'HierarchyTree')?>?hierarchy=<?=urlencode($hierarchy)?>"><?=$this->escapeHtml($hierarchyTitle)?></a>
+      <? endforeach; ?>
+    </div>
+  <? endif; ?>
+  <? if ($activeTree): ?>
+    <div id="hierarchyTreeHolder">
+      <div id="hierarchyTree">
+        <?=$this->tab->renderTree($this->url('home'))?>
+      </div>
+    </div>
+  <? endif; ?>
+</div>
diff --git a/themes/jquerymobile/templates/RecordTab/hierarchytree.phtml b/themes/jquerymobile/templates/RecordTab/hierarchytree.phtml
new file mode 100644
index 00000000000..656aaf248f6
--- /dev/null
+++ b/themes/jquerymobile/templates/RecordTab/hierarchytree.phtml
@@ -0,0 +1,22 @@
+<?
+    // Set page title.
+    $this->headTitle($this->translate('hierarchy_tree') . ': ' . $this->driver->getBreadcrumb());
+    $hierarchyTreeList = $this->tab->getTreeList();
+    $activeTree = $this->tab->getActiveTree();
+?>
+<div>
+  <? if (count($hierarchyTreeList) > 1): ?>
+    <div id="treeSelector">
+      <? foreach ($hierarchyTreeList as $hierarchy => $hierarchyTitle): ?>
+        <a class="tree<?=($activeTree == $hierarchy) ? ' currentTree' : ''?>" href="<?=$this->recordLink()->getTabUrl($this->driver, 'HierarchyTree')?>?hierarchy=<?=urlencode($hierarchy)?>"><?=$this->escapeHtml($hierarchyTitle)?></a>
+      <? endforeach; ?>
+    </div>
+  <? endif; ?>
+  <? if ($activeTree): ?>
+    <div id="hierarchyTreeHolder">
+      <div id="hierarchyTree">
+        <?=$this->tab->renderTree($this->url('home'))?>
+      </div>
+    </div>
+  <? endif; ?>
+</div>
-- 
GitLab