From a2e06f3d79c1255352ef7a340013b267cf9aee71 Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Tue, 2 Jul 2013 15:45:05 -0400
Subject: [PATCH] Configurable tabs for switching between search modules.
 Resolves VUFIND-107.

---
 config/vufind/config.ini                      |  10 +-
 .../VuFind/View/Helper/Root/SearchTabs.php    | 233 ++++++++++++++++++
 themes/blueprint/css/styles.css               |  25 ++
 .../templates/search/searchbox.phtml          |  18 ++
 themes/root/theme.config.php                  |   9 +
 5 files changed, 294 insertions(+), 1 deletion(-)
 create mode 100644 module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php

diff --git a/config/vufind/config.ini b/config/vufind/config.ini
index 344d2c6161a..330b99adc99 100644
--- a/config/vufind/config.ini
+++ b/config/vufind/config.ini
@@ -873,4 +873,12 @@ max_tag_length = 64
 
 ; Uncomment this section and provide your API key to enable Google Analytics
 ;[GoogleAnalytics]
-;apiKey = "mykey"
\ No newline at end of file
+;apiKey = "mykey"
+
+; Uncomment portions of this section to activate tabs in the search box for switching
+; between search modules. Keys are search backend names, values are labels for use in
+; the user interface (subject to translation).
+[SearchTabs]
+;Solr = Catalog
+;Summon = Summon
+;WorldCat = WorldCat
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php b/module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php
new file mode 100644
index 00000000000..2b99e7c8324
--- /dev/null
+++ b/module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ * "Search tabs" view helper
+ *
+ * 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  View_Helpers
+ * @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/vufind2:developer_manual Wiki
+ */
+namespace VuFind\View\Helper\Root;
+use VuFind\Search\Results\PluginManager, Zend\View\Helper\Url;
+
+/**
+ * "Search tabs" view helper
+ *
+ * @category VuFind2
+ * @package  View_Helpers
+ * @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/vufind2:developer_manual Wiki
+ */
+class SearchTabs extends \Zend\View\Helper\AbstractHelper
+{
+    /**
+     * Search manager
+     *
+     * @var PluginManager
+     */
+    protected $results;
+
+    /**
+     * Tab configuration
+     *
+     * @var array
+     */
+    protected $config;
+
+    /**
+     * URL helper
+     *
+     * @var Url
+     */
+    protected $url;
+
+    /**
+     * Constructor
+     *
+     * @param PluginManager $results Search results plugin manager
+     * @param array         $config  Tab configuration
+     * @param Url           $url     URL helper
+     */
+    public function __construct(PluginManager $results, array $config, Url $url)
+    {
+        $this->results = $results;
+        $this->config = $config;
+        $this->url = $url;
+    }
+
+    /**
+     * Determine information about search tabs
+     *
+     * @param string $activeSearchClass The search class ID of the active search
+     * @param string $query             The current search query
+     * @param string $handler           The current search handler
+     * @param string $type              The current search type (basic/advanced)
+     *
+     * @return array
+     */
+    public function __invoke($activeSearchClass, $query, $handler, $type = 'basic')
+    {
+        $retVal = array();
+        foreach ($this->config as $class => $label) {
+            if ($class == $activeSearchClass) {
+                $retVal[] = $this->createSelectedTab($class, $label);
+            } else if ($type == 'basic') {
+                if (!isset($activeOptions)) {
+                    $activeOptions
+                        = $this->results->get($activeSearchClass)->getOptions();
+                }
+                $newUrl = $this
+                    ->remapBasicSearch($activeOptions, $class, $query, $handler);
+                $retVal[] = $this->createBasicTab($class, $label, $newUrl);
+            } else if ($type == 'advanced') {
+                $retVal[] = $this->createAdvancedTab($class, $label);
+            } else {
+                $retVal[] = $this->createHomeTab($class, $label);
+            }
+        }
+        return $retVal;
+    }
+
+    /**
+     * Create information representing a selected tab.
+     *
+     * @param string $class Search class ID
+     * @param string $label Display text for tab
+     *
+     * @return array
+     */
+    protected function createSelectedTab($class, $label)
+    {
+        return array(
+            'class' => $class,
+            'label' => $label,
+            'selected' => true
+        );
+    }
+
+    /**
+     * Map a search query from one class to another.
+     *
+     * @param \VuFind\Search\Base\Options $activeOptions Search options for source
+     * @param string                      $targetClass   Search class ID for target
+     * @param string                      $query         Search query to map
+     * @param string                      $handler       Search handler to map
+     *
+     * @return string
+     */
+    protected function remapBasicSearch($activeOptions, $targetClass, $query,
+        $handler
+    ) {
+        // Get label for source handler:
+        $sourceLabel = false;
+        foreach ($activeOptions->getBasicHandlers() as $id => $label) {
+            if ($handler == $id) {
+                $sourceLabel = $label;
+            }
+        }
+
+        // Set up results object for URL building:
+        $results = $this->results->get($targetClass);
+        $options = $results->getOptions();
+
+        // Find matching handler for new query (and use default if no match):
+        $targetHandler = false;
+        foreach ($options->getBasicHandlers() as $id => $label) {
+            if ($label == $sourceLabel) {
+                $targetHandler = $id;
+            }
+        }
+        if (!$targetHandler) {
+            $targetHandler = $options->getDefaultHandler();
+        }
+
+        // Build new URL:
+        $results->getParams()->setBasicSearch($query, $targetHandler);
+        return $this->url->__invoke($options->getSearchAction())
+            . $results->getUrlQuery()->getParams(false);
+    }
+
+    /**
+     * Create information representing a basic search tab.
+     *
+     * @param string $class  Search class ID
+     * @param string $label  Display text for tab
+     * @param string $newUrl Target search URL
+     *
+     * @return array
+     */
+    protected function createBasicTab($class, $label, $newUrl)
+    {
+        return array(
+            'class' => $class,
+            'label' => $label,
+            'selected' => false,
+            'url' => $newUrl
+        );
+    }
+
+    /**
+     * Create information representing a tab linking to "search home."
+     *
+     * @param string $class Search class ID
+     * @param string $label Display text for tab
+     *
+     * @return array
+     */
+    protected function createHomeTab($class, $label)
+    {
+        // If an advanced search is available, link there; otherwise, just go
+        // to the search home:
+        $options = $this->results->get($class)->getOptions();
+        $url = $this->url->__invoke($options->getSearchHomeAction());
+        return array(
+            'class' => $class,
+            'label' => $label,
+            'selected' => false,
+            'url' => $url
+        );
+    }
+
+    /**
+     * Create information representing an advanced search tab.
+     *
+     * @param string $class Search class ID
+     * @param string $label Display text for tab
+     *
+     * @return array
+     */
+    protected function createAdvancedTab($class, $label)
+    {
+        // If an advanced search is available, link there; otherwise, just go
+        // to the search home:
+        $options = $this->results->get($class)->getOptions();
+        $advSearch = $options->getAdvancedSearchAction();
+        $url = $this->url
+            ->__invoke($advSearch ? $advSearch : $options->getSearchHomeAction());
+        return array(
+            'class' => $class,
+            'label' => $label,
+            'selected' => false,
+            'url' => $url
+        );
+    }
+}
\ No newline at end of file
diff --git a/themes/blueprint/css/styles.css b/themes/blueprint/css/styles.css
index 68bd82c88d0..66b431dfc6f 100644
--- a/themes/blueprint/css/styles.css
+++ b/themes/blueprint/css/styles.css
@@ -2108,4 +2108,29 @@ div.handle {
     color: white;
     font: bold 15px/30px 'lucida sans', 'trebuchet MS', 'Tahoma';
     z-index: 10;
+}
+
+.searchTabNav {
+    border-bottom:1px solid #619144;
+    display:table;
+    list-style:none;
+    padding:0 10px 1px 10px;
+}
+.searchTabNav li {
+    background:#EFD;
+    border:1px solid #619144;
+    display:inline;
+    font-size:10pt;
+    margin:0 1px;
+    padding:3px 6px;
+    text-align:center;
+    width:60px;
+}
+.searchTabNav li.active {
+    background:#FFF;
+    border-bottom:1px solid #FFF;
+}
+.searchTabNav li.active a {
+    color:#000;
+    text-decoration:none;
 }
\ No newline at end of file
diff --git a/themes/blueprint/templates/search/searchbox.phtml b/themes/blueprint/templates/search/searchbox.phtml
index 6aa28a4315e..fb8d70216da 100644
--- a/themes/blueprint/templates/search/searchbox.phtml
+++ b/themes/blueprint/templates/search/searchbox.phtml
@@ -13,6 +13,24 @@
     $lastLimit = $options->getLastLimit();
 ?>
 <div class="searchform">
+  <? $searchTabs = $this->searchtabs($this->searchClassId, $this->lookfor, $this->searchIndex, $this->searchType); ?>
+  <? if (count($searchTabs) > 0): ?>
+    <ul class="searchTabNav">
+    <? foreach ($searchTabs as $tab): ?>
+      <li<?=$tab['selected'] ? ' class="active"' : ''?>>
+        <?
+          if (!$tab['selected']) {
+            echo '<a href="' . $this->escapeHtml($tab['url']) . '">';
+          }
+          echo $this->transEsc($tab['label']);
+          if (!$tab['selected']) {
+            echo '</a>';
+          }
+        ?>
+      </li>
+    <? endforeach; ?>
+    </ul>
+  <? endif; ?>
   <? if ($this->searchType == 'advanced'): ?>
     <a href="<?=$this->url($advSearch)?>?edit=<?=$this->escapeHtml($this->searchId)?>" class="small"><?=$this->transEsc("Edit this Advanced Search")?></a> |
     <a href="<?=$this->url($advSearch)?>" class="small"><?=$this->transEsc("Start a new Advanced Search")?></a> |
diff --git a/themes/root/theme.config.php b/themes/root/theme.config.php
index 37fc11c2ee6..9f0a28fc951 100644
--- a/themes/root/theme.config.php
+++ b/themes/root/theme.config.php
@@ -108,6 +108,15 @@ return array(
                     $sm->getServiceLocator()->get('VuFind\SearchOptionsPluginManager')
                 );
             },
+            'searchtabs' => function ($sm) {
+                $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config');
+                $config = isset($config->SearchTabs)
+                    ? $config->SearchTabs->toArray() : array();
+                return new VuFind\View\Helper\Root\SearchTabs(
+                    $sm->getServiceLocator()->get('VuFind\SearchResultsPluginManager'),
+                    $config, $sm->get('url')
+                );
+            },
             'syndeticsplus' => function ($sm) {
                 $config = $sm->getServiceLocator()->get('VuFind\Config')->get('config');
                 return new \VuFind\View\Helper\Root\SyndeticsPlus(
-- 
GitLab