From e4cbffc32d6610032e2dd1a2969f28b025e6485d Mon Sep 17 00:00:00 2001
From: Chris Hallberg <crhallberg@gmail.com>
Date: Thu, 2 Feb 2017 15:54:05 -0500
Subject: [PATCH] Searchbox Placeholders (#885)

---
 config/vufind/config.ini                      | 16 +++++++++
 .../src/VuFind/View/Helper/Root/Factory.php   |  5 ++-
 .../src/VuFind/View/Helper/Root/SearchBox.php | 34 +++++++++++++++++--
 .../VuFind/View/Helper/Root/SearchTabs.php    | 24 +++++++------
 .../templates/search/searchTabs.phtml         |  1 -
 .../templates/search/searchbox.phtml          |  8 +++--
 6 files changed, 71 insertions(+), 17 deletions(-)

diff --git a/config/vufind/config.ini b/config/vufind/config.ini
index 50d7dfc919a..182cbcdd157 100644
--- a/config/vufind/config.ini
+++ b/config/vufind/config.ini
@@ -1507,6 +1507,22 @@ treeSearchLimit = 100
 ; Use * for all supported forms
 ;forms = changePassword, email, newAccount, passwordRecovery, sms
 
+
+; This section can be used to display default text inside the search boxes, useful
+; for instructions. Format:
+;
+; backend = Placeholder text
+;
+; You can use a "default" setting if you want a standard string displayed across
+; all backends not otherwise specified. You can qualify backend names with a
+; colon-delimited suffix if you wish to use special placeholders in combination
+; with filtered search tabs (see [SearchTabsFilters] above).
+[SearchPlaceholder]
+;default = "Enter search terms here..."
+;Solr = "Search the catalog"
+;Solr:filtered = "Search the filtered catalog"
+;Summon = "Search Summon"
+
 ; This section controls VuFind's social features.
 [Social]
 ; Comments may be "enabled" or "disabled" (default = "enabled")
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/Factory.php b/module/VuFind/src/VuFind/View/Helper/Root/Factory.php
index 340d1b8154f..9544456c0bd 100644
--- a/module/VuFind/src/VuFind/View/Helper/Root/Factory.php
+++ b/module/VuFind/src/VuFind/View/Helper/Root/Factory.php
@@ -444,9 +444,12 @@ class Factory
     public static function getSearchBox(ServiceManager $sm)
     {
         $config = $sm->getServiceLocator()->get('VuFind\Config');
+        $mainConfig = $config->get('config');
         return new SearchBox(
             $sm->getServiceLocator()->get('VuFind\SearchOptionsPluginManager'),
-            $config->get('searchbox')->toArray()
+            $config->get('searchbox')->toArray(),
+            isset($mainConfig->SearchPlaceholder)
+                ? $mainConfig->SearchPlaceholder->toArray() : []
         );
     }
 
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/SearchBox.php b/module/VuFind/src/VuFind/View/Helper/Root/SearchBox.php
index a4fb93bc11c..ad912bf51d4 100644
--- a/module/VuFind/src/VuFind/View/Helper/Root/SearchBox.php
+++ b/module/VuFind/src/VuFind/View/Helper/Root/SearchBox.php
@@ -46,6 +46,13 @@ class SearchBox extends \Zend\View\Helper\AbstractHelper
      */
     protected $config;
 
+    /**
+     * Placeholders from config.ini
+     *
+     * @var array
+     */
+    protected $placeholders;
+
     /**
      * Search options plugin manager
      *
@@ -65,11 +72,14 @@ class SearchBox extends \Zend\View\Helper\AbstractHelper
      *
      * @param OptionsManager $optionsManager Search options plugin manager
      * @param array          $config         Configuration for search box
+     * @param array          $placeholders   Array of placeholders keyed by backend
      */
-    public function __construct(OptionsManager $optionsManager, $config = [])
-    {
+    public function __construct(OptionsManager $optionsManager, $config = [],
+        $placeholders = []
+    ) {
         $this->optionsManager = $optionsManager;
         $this->config = $config;
+        $this->placeholders = $placeholders;
     }
 
     /**
@@ -155,6 +165,26 @@ class SearchBox extends \Zend\View\Helper\AbstractHelper
         return $final;
     }
 
+    /**
+     * Get placeholder text from config using the activeSearchClass as key
+     *
+     * @param string $activeSearchClass Active search class ID
+     *
+     * @return string
+     */
+    public function getPlaceholderText($activeSearchClass)
+    {
+        // Searchbox place
+        if (!empty($this->placeholders)) {
+            return isset($this->placeholders[$activeSearchClass])
+                ? $this->placeholders[$activeSearchClass]
+                : (isset($this->placeholders['default'])
+                    ? $this->placeholders['default']
+                    : null);
+        }
+        return null;
+    }
+
     /**
      * Get an array of information on search handlers for use in generating a
      * drop-down or hidden field. Returns an array of arrays with 'value', 'label',
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php b/module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php
index 04735d9feea..af6f87fcb52 100644
--- a/module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php
+++ b/module/VuFind/src/VuFind/View/Helper/Root/SearchTabs.php
@@ -110,8 +110,7 @@ class SearchTabs extends \Zend\View\Helper\AbstractHelper
     public function getTabConfig($activeSearchClass, $query, $handler,
         $type = 'basic', $hiddenFilters = []
     ) {
-        $retVal = [];
-        $matchFound = false;
+        $retVal = ['tabs' => []];
         $allFilters = $this->helper->getTabFilterConfig();
         foreach ($this->helper->getTabConfig() as $key => $label) {
             $class = $this->helper->extractClassName($key);
@@ -119,8 +118,8 @@ class SearchTabs extends \Zend\View\Helper\AbstractHelper
             if ($class == $activeSearchClass
                 && $this->helper->filtersMatch($class, $hiddenFilters, $filters)
             ) {
-                $matchFound = true;
-                $retVal[] = $this->createSelectedTab($key, $class, $label);
+                $retVal['selected'] = $this->createSelectedTab($key, $class, $label);
+                $retVal['tabs'][] = $retVal['selected'];
             } else if ($type == 'basic') {
                 if (!isset($activeOptions)) {
                     $activeOptions
@@ -129,17 +128,21 @@ class SearchTabs extends \Zend\View\Helper\AbstractHelper
                 $newUrl = $this->remapBasicSearch(
                     $activeOptions, $class, $query, $handler, $filters
                 );
-                $retVal[] = $this->createBasicTab($key, $class, $label, $newUrl);
+                $retVal['tabs'][]
+                    = $this->createBasicTab($key, $class, $label, $newUrl);
             } else if ($type == 'advanced') {
-                $retVal[] = $this->createAdvancedTab($key, $class, $label, $filters);
+                $retVal['tabs'][]
+                    = $this->createAdvancedTab($key, $class, $label, $filters);
             } else {
-                $retVal[] = $this->createHomeTab($key, $class, $label, $filters);
+                $retVal['tabs'][]
+                    = $this->createHomeTab($key, $class, $label, $filters);
             }
         }
-        if (!$matchFound && !empty($retVal)) {
+        if (!isset($retVal['selected']) && !empty($retVal['tabs'])) {
             // Make the first tab for the given search class selected
-            foreach ($retVal as &$tab) {
+            foreach ($retVal['tabs'] as &$tab) {
                 if ($tab['class'] == $activeSearchClass) {
+                    $retVal['selected'] = $tab;
                     $tab['selected'] = true;
                     break;
                 }
@@ -158,11 +161,12 @@ class SearchTabs extends \Zend\View\Helper\AbstractHelper
      */
     public function getTabConfigForParams($params)
     {
-        return $this->getTabConfig(
+        $tabConfig = $this->getTabConfig(
             $params->getSearchClassId(), $params->getDisplayQuery(),
             $params->getSearchHandler(), $params->getSearchType(),
             $params->getHiddenFilters()
         );
+        return $tabConfig['tabs'];
     }
 
     /**
diff --git a/themes/bootstrap3/templates/search/searchTabs.phtml b/themes/bootstrap3/templates/search/searchTabs.phtml
index 05ba2bf5cf6..31ad4e7f543 100644
--- a/themes/bootstrap3/templates/search/searchTabs.phtml
+++ b/themes/bootstrap3/templates/search/searchTabs.phtml
@@ -1,4 +1,3 @@
-<? $searchTabs = $this->searchtabs()->getTabConfig($this->searchClassId, $this->lookfor, $this->searchIndex, $this->searchType, $this->hiddenFilters); ?>
 <? if (count($searchTabs) > 0): ?>
   <ul class="nav nav-tabs">
     <? foreach ($searchTabs as $tab): ?>
diff --git a/themes/bootstrap3/templates/search/searchbox.phtml b/themes/bootstrap3/templates/search/searchbox.phtml
index 1483a029117..7361d9d0058 100644
--- a/themes/bootstrap3/templates/search/searchbox.phtml
+++ b/themes/bootstrap3/templates/search/searchbox.phtml
@@ -27,9 +27,10 @@
     }
     $hiddenFilterParams = $this->searchtabs()->getCurrentHiddenFilterParams($this->searchClassId, $ignoreHiddenFilterMemory, '?');
 ?>
+<? $searchTabs = $this->searchtabs()->getTabConfig($this->searchClassId, $this->lookfor, $this->searchIndex, $this->searchType, $hiddenFilters); ?>
 <? if ($this->searchType == 'advanced'): ?>
   <div class="navbar-form navbar-left flip">
-    <? $tabs = $this->context($this)->renderInContext('search/searchTabs', ['hiddenFilters' => $hiddenFilters]); ?>
+    <? $tabs = $this->context($this)->renderInContext('search/searchTabs', ['searchTabs' => $searchTabs['tabs']]); ?>
     <? if (!empty($tabs)): ?><?=$tabs ?><div class="tab-content clearfix"><? endif; ?>
       <p class="adv_search_terms"><?=$this->transEsc("Your search terms")?> : "<strong><?=$this->escapeHtml($this->lookfor)?></strong>"</p>
       <p class="adv_search_links">
@@ -41,8 +42,9 @@
   </div>
 <? else: ?>
   <form id="searchForm" class="searchForm navbar-form navbar-left flip" method="get" action="<?=$this->url($basicSearch)?>" name="searchForm" autocomplete="off">
-    <?= $this->context($this)->renderInContext('search/searchTabs', ['hiddenFilters' => $hiddenFilters]); ?>
-    <input id="searchForm_lookfor" class="searchForm_lookfor form-control search-query<? if($this->searchbox()->autocompleteEnabled($this->searchClassId)):?> autocomplete searcher:<?=$this->escapeHtmlAttr($this->searchClassId) ?><? endif ?>" type="text" name="lookfor" value="<?=$this->escapeHtmlAttr($this->lookfor)?>" autofocus />
+    <?= $this->context($this)->renderInContext('search/searchTabs', ['searchTabs' => $searchTabs['tabs']]); ?>
+    <? $placeholder = $this->searchbox()->getPlaceholderText($searchTabs['selected']['id']); ?>
+    <input id="searchForm_lookfor" class="searchForm_lookfor form-control search-query<? if($this->searchbox()->autocompleteEnabled($this->searchClassId)):?> autocomplete searcher:<?=$this->escapeHtmlAttr($this->searchClassId) ?><? endif ?>" type="text" name="lookfor" value="<?=$this->escapeHtmlAttr($this->lookfor)?>"<? if ($placeholder): ?> placeholder="<?=$placeholder ?>"<? endif ?> autofocus />
     <? if ($handlerCount > 1): ?>
       <select id="searchForm_type" class="searchForm_type form-control" name="type" data-native-menu="false">
         <? foreach ($handlers as $handler): ?>
-- 
GitLab