SearchJS Module


Introduction

Studio JS UX Accelerator provides a Vue.js Based Search Interface to integrate with your SearchStudio Application. It serves PCs, tablets, and mobile platforms with equal facility.

Search environment for laptop and tablet.
Search environment for mobile phone.

The SearchJS Module allows users to:

  • Search using keywords
  • Show search results in grid or list format
  • Track searches and clicks for analysis
  • Search with auto-suggest/ auto-complete feature
  • Show facets (refinements) as configured in SearchStudio
  • Pagination of search results
  • Result sorting by customizable options.
  • Show did-you-mean suggestions for misspellings
  • Ability to apply transformation functions to show fields
  • Ability to submit feedback for tracking and analysis

Studio JS – JS/CSS Libraries:

To integrate Studio JS, download the following JS and CSS files or include them directly on your webpage:

  • https://static.searchstax.com/studio-js/v2.5/css/studio-app.css
  • https://static.searchstax.com/studio-js/v2.5/js/studio-app.js
  • https://static.searchstax.com/studio-js/v2.5/js/studio-vendors.js
  • https://static.searchstax.com/studio-js/v2.5/js/studio-analytics.js
  • https://static.searchstax.com/studio-js/v2.5/js/studio-feedback.js (Optional to include Search Feedback)

The above integrates a specific version of the library. To get the latest v2 version, use the following:

  • https://static.searchstax.com/studio-js/v2/css/studio-app.css
  • https://static.searchstax.com/studio-js/v2/js/studio-app.js
  • https://static.searchstax.com/studio-js/v2/js/studio-vendors.js
  • https://static.searchstax.com/studio-js/v2/js/studio-analytics.js
  • https://static.searchstax.com/studio-js/v2/js/studio-feedback.js (Optional to include Search Feedback)

Studio JS Integration

  1. Include the downloaded files or hosted version of these files in the head section of the HTML page
<script type="text/javascript">
     var _msq = _msq || []; //declare object
     var analyticsBaseUrl = 'https://app.searchstax.com';
     (function () {
       var ms = document.createElement("script");
       ms.type = "text/javascript";
       ms.src = "https://static.searchstax.com/studio-js/v2/js/studio-analytics.js";
       var s = document.getElementsByTagName("script")[0];
       s.parentNode.insertBefore(ms, s);
     })();
</script>
<link href=https://static.searchstax.com/studio-js/v2/css/studio-app.css rel=preload as=style />
<link href=https://static.searchstax.com/studio-js/v2/js/studio-app.js rel=preload as=script />
<link href=https://static.searchstax.com/studio-js/v2/js/studio-vendors.js rel=preload as=script />
<link href=https://static.searchstax.com/studio-js/v2/css/studio-app.css rel=stylesheet />
  1. Define the DIVs in your HTML where the search box and various other components should be shown:
<div id="searchInput"></div>
 <div id="searchResultSummarySection"></div>
 <div id="searchOptionsSection"></div>
 <div id="searchFacetSection"></div>
 <div id="searchResultsSection"></div>

  • searchInput is the input textbox for Search
  • searchResultSummarySection is the are where summary of the search results should be shown. Example: Showing 1-10 of 200 results for Sitecore
  • searchOptionsSection is the section where options for display (list/grid) and Sort Options are shown.
  • searchFacetSection is the area for showing the Facets/Filters
  • searchResultsSection is the area for showing the Search Results
  • These divs can be styled and be located as per your web design.
  1. Optionally, define the DIV in your HTML where the Search Feedback link should be shown:
<div id="sf-feedback"></div>
  1. Initialize the search box by providing information about your Studio Application endpoints and keys as shown below:
<script>
      const studioConfig = {
        "connector": {
          "url": "https://XXXXX.searchstax.com/solr/ss-sample/emselect",
          "authentication": "YXBwNDMtYXBpOkNhbGl4IzIz",
          "apikey": "9irZHJbDKzVGnjJjEGgzOVWLt8e2OAHv6krBuf5uvSY",
          "session": session,
          "fields": {
            "title": "ds_title",
            "url": "site_url",
            "ribbon": "category",
            "date": "ds_field_display_date",
            "thumbnail": "image_s"
          },
          fieldFormatters: {
            "ds_field_display_date": format_date
          }
 
          searchAdditionalArgs: "hl.fragsize=200",
          suggester: "https://XXXXX.searchstax.com/solr/ss-sample-suggester-3/emsuggest",
       hideUniqueKey: false,
        },
       searchResults: '#searchResultsSection',
       searchInput: '#searchInput',
       searchResultSummarySection: '#searchResultSummarySection',
       facetSection: '#searchFacetContainer',
       searchOptionsSection: '#searchOptionsSection',
       hideBranding: false,
       display: "multi",
       facet_pagination: 4,
       customResultTemplate: '#result-template'
 
      };
    </script>

  • connector.url: required: This is the Search Engine URL for your Studio Application
  • connector.suggester: optional: This is the Auto-Suggest URL for your Studio Application
  • connector.authentication: required: This is the Basic Authentication header for the Search Endpoint. You can construct this from the API username/password that was used when configuring the Studio Application – https://www.blitter.se/utils/basic-authentication-header-generator/
  • connector.apiKey –  required: This is the Analytics tracking key that you can find in your Studio Application settings – https://searchstudio.searchstax.com/#/apps-management
  • connector.sessionrequired: Unique session id that should be passed to track the user. 
  • connector.fieldsrequired: Studio JS shows certain fields in a special way. These special fields are:
    • titlerequired: This is shows as the header, on clicking which the “url” is opened
    • urlrequired: Field containing the URL that will be tracked and opened when the title is clicked on
    • ribbonoptional: Field whose data will be shown at the top of the tile as a ribbon. For example, in the image below, Documentation is shown as a ribbon.
    • date: optional: Field that contains the date. Only if this field is present, sorting options to show search results by Relevance or Most Recent will be shown.
    • thumbnail: optional: Field that contains the url of an image that should be shown in a special way as a thumbnail to the left of the search result item.
  • fieldFormatters: optional: can be used to transform any field. For example, if your dataset contains the field as a long, or any other format, you can write a formatter to transform it into a readable date string. As shown in the example, for any of the fields, you can specify the formatter function that the module should call when showing the value of that particular field.
  • hideUniqueKey: optional: can be used to hide the value of the Unique id/key (as defined in the schema) from the search results that are shown. Sometimes, the unique key is a url and you would like to display it, while sometimes it might be a UUID that you would not like to display.
  • connector.searchAdditionalArgs: optional:  can be used to add any additional parameters that you would like to add to the Solr select endpoint. Example: “hl.fragsize=200&hl.simple.pre=<font color=’red’>&hl.simple.post=</font>”
  • display: optional:  lets you control how the search results will be shown. Available options are grid(default), list and multi (Shows toggle option between list and grid)
  • hideBranding: optional: Setting this value to True hides SearchStax branding from the SearchBox
  • searchResults: The div for showing the search results
  • searchInput: The div for showing the search input textbox
  • searchResultSummarySection: The div for showing the summary of search results (Like Showing 1-10 of 200 results for “Sitecore)
  • facetSection: The div for showing the facets/filters
  • searchResults: The div for showing the search results
  • searchOptionsSection: The div for showing the search options for sorting and display styles
  • customResultTemplate: optional: If provided this custom text/x-template can be used for customizing the layout for search results. You can style the results as you like using the template. This will require some knowledge on how to write Vue templates. The variables available in the template are:
  1. isGridLayout: Dynamic internal function that returns true if the layout is grid. You can use this to specify a different CSS for Grid Layout vs List Layout
  2. ribbon: Data for the configured ribbon field as returned by the search
  3. title: Data for the configured title field as returned by the search
  4. url: Data for the configured url field as returned by the search
  5. paths: Data for the configured paths field as returned by the search
  6. thumbail: Data for the configured thumbnail field as returned by the search
  7. date: Data for the configured date field as returned by the search
  8. snippet: Data for the configured snippet field as returned by the search
  9. result: contains all unparsed result data for more complex implementations
  10. promoted: Contains flag if the search result is promoted (true/false)

For the result to be clickable, a property @click=”navigate” should be placed on the tag.

Below are 2 example templates: Template 1: Show all configured fields.

<script type="text/x-template" id="result-template">
   <div class="card-custom" :class="{'card-grid-layout': isGridLayout, 'has-thumbnail': thumbnail !== ''}">
     <div :class="cardClass">
          <div class="card-body p-0">
               <span class="badge" v-if="ribbon" v-html="ribbon" />
               <div class="card-title" v-if="title">
                  <a class="stretched-link" v-if="url" :href="url" @click="navigate" v-html="title" />
                  <span v-else v-html="title" />
               </div>
               <span class="card-path" v-if="paths" v-html="paths" />
               <span class="star elevated" v-if="promoted">&nbsp;</span>
               <div class="thumbnail" v-if="thumbnail"><span><img :src="thumbnail"></span></div>
 
               <div class="card-body p-0" v-if="date || snippet">
                  <div v-if="date"><div class="card-text"><span v-html="date" /></div></div>
                  <div v-if="snippet"><div class="card-text"><span v-html="snippet" /></div></div>
               </div>
          </div>
     </div>
   </div>
</script>

Template 2: Show standard fields, and have a way to loop through and show any extra fields returned by the search, which are present in the raw result variable:

<script type="text/x-template" id="result-template">
   <div class="card-custom" :class="{'card-grid-layout': isGridLayout, 'has-thumbnail': thumbnail !== ''}">
     <div :class="cardClass">
          <div class="card-body p-0">
           <span class="badge" v-if="ribbon" v-html="ribbon" />
           <div class="card-title" v-if="title">
               <a class="stretched-link" v-if="url" :href="url" @click="navigate" v-html="title" />
               <span v-else v-html="title" />
           </div>
           <span class="card-path" v-if="paths" v-html="paths" />
           <span class="star elevated" v-if="promoted">&nbsp;</span>
           <div class="thumbnail" v-if="thumbnail"><span><img :src="thumbnail"></span></div>
 
           <div class="card-body p-0" :key="propertyName" v-for="(value, propertyName) in result">
           <div v-if="displayProperty(value, propertyName)">
                     <div class="card-text" :class="propertyName">
              <span class="image" v-if="isImage(value)"><img :src="value" /> </span>
              <span class=valueClass(value) v-html="extractedValue(propertyName, value)" v-else />
          </div>
       </div>
         </div>
       </div>
     </div>
  </div>
</script>

Below is the CSS that can be used as an example for the above templates:

<style type="text/css">
     .card-custom {
        position: relative;
        padding: 39px 12px 28px 12px;
        color: #33475a;
        border: none;
        /* box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.14902); */
      }
      .card-custom.has-thumbnail {
        padding-left: 35%;
      }
      .card-custom.has-thumbnail .thumbnail {
        position: absolute;
        left: 0;
        top: 0;
        height: 100%;
        max-height: 230px;
        width: 33.33%;
        overflow: hidden;
      }
      .card-custom.has-thumbnail .thumbnail span {
        display: block;
        height: 100%;
        width: 100%;
      }
      .card-custom.has-thumbnail .badge {
        left: 35%;
        border-top-left-radius: 0;
      }
      .card-custom.card-grid-layout {
        height: 100%;
      }
      .card-custom.card-grid-layout.has-thumbnail {
        padding-top: 250px;
        padding-left: 12px;
      }
      .card-custom.card-grid-layout.has-thumbnail .thumbnail {
        height: 200px;
        overflow: hidden;
        position: absolute;
        left: 0;
        top: 35px;
        width: 100%;
      }
      .card-custom.card-grid-layout.has-thumbnail .badge {
        left: 0;
        width: 100%;
        min-height: 35px;
      }
      .card-custom:hover {
        background-color: rgba(0, 0, 0, 0.02);
      }
      .card-custom .badge {
        position: absolute;
        left: 0;
        top: 0;
        display: flex;
        align-items: center;
        text-align: left;
        padding: 0 10px;
        min-width: 135px;
        min-height: 24px;
        color: #fff;
        font-family: 'Roboto';
        font-weight: 500;
        text-transform: uppercase;
        font-size: 12px;
        text-transform: uppercase;
        border-radius: 3px 0 0 0;
        background-color: #33475a;
      }
      .card-custom .star {
        position: absolute;
        right: 0;
        top: 0;
        text-align: center;
        padding: 4px;
        width: 28px;
        height: 24px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: #fff;
        font-family: 'Roboto';
        font-weight: 500;
        text-transform: uppercase;
        font-size: 12px;
        border-radius: 0 3px 0 0;
        background-color: #33475a;
        background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbG5zOnN2Z2pzPSJodHRwOi8vc3ZnanMuY29tL3N2Z2pzIiB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgeD0iMCIgeT0iMCIgdmlld0JveD0iMCAwIDE5LjQ4MSAxOS40ODEiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTIiIHhtbDpzcGFjZT0icHJlc2VydmUiIGNsYXNzPSIiPjxnPgogIDxnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8cGF0aCBkPSJtMTAuMjAxLC43NThsMi40NzgsNS44NjUgNi4zNDQsLjU0NWMwLjQ0LDAuMDM4IDAuNjE5LDAuNTg3IDAuMjg1LDAuODc2bC00LjgxMiw0LjE2OSAxLjQ0Miw2LjIwMmMwLjEsMC40MzEtMC4zNjcsMC43Ny0wLjc0NSwwLjU0MWwtNS40NTItMy4yODgtNS40NTIsMy4yODhjLTAuMzc5LDAuMjI4LTAuODQ1LTAuMTExLTAuNzQ1LTAuNTQxbDEuNDQyLTYuMjAyLTQuODEzLTQuMTdjLTAuMzM0LTAuMjg5LTAuMTU2LTAuODM4IDAuMjg1LTAuODc2bDYuMzQ0LS41NDUgMi40NzgtNS44NjRjMC4xNzItMC40MDggMC43NDktMC40MDggMC45MjEsMHoiIGZpbGw9IiNmZmZmZmYiIGRhdGEtb3JpZ2luYWw9IiMwMDAwMDAiIHN0eWxlPSIiIGNsYXNzPSIiPjwvcGF0aD4KICA8L2c+CjwvZz48L3N2Zz4=');
        background-size: 12px;
        background-repeat: no-repeat;
        background-position: center center;
      }
      .card-custom .card-title {
        font-size: 18px;
        font-family: 'Roboto';
        font-weight: 400;
        line-height: 22px;
        margin-bottom: 0;
      }
      .card-custom .card-title a {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        /* number of lines to show */
        -webkit-box-orient: vertical;
        padding: 0;
        color: #33475a;
      }
      .card-custom .card-title a:hover {
        text-decoration: none;
      }
      .card-custom .card-title small {
        font-size: 13px;
        font-family: 'Roboto';
        font-weight: 300;
      }
      .card-custom .card-path {
        margin-bottom: 8px;
        font-size: 14px;
        font-family: 'Roboto';
        font-weight: 300;
        line-height: 1.2;
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 1;
        /* number of lines to show */
        -webkit-box-orient: vertical;
      }
      .card-custom .card-text span {
        font-size: 14px;
        font-family: 'Roboto';
        font-weight: 300;
        line-height: 21px;
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 3;
        /* number of lines to show */
        -webkit-box-orient: vertical;
      }
      .card-custom .card-text span .stretched-link {
        color: #33475a;
      }
      .card-custom .card-text span em {
        font-weight: 400;
      }
      .card-custom .card-text .image {
        height: 75px;
        width: 75px;
        overflow: hidden;
      }
      .card-custom .card-text .image img {
        width: 100%;
        height: auto;
      }
      .card-custom .card-title strong,
      .card-custom .card-text strong {
        color: #fc6730;
      }
      .card-custom .card-body img {
        width: 100%;
      }
      /* Custom style for result END*/
    </style>

  1. If using the Optional Search Feedback, initialize the plugin as shown below:
<script type="text/javascript">
     (function (w,d,s,o,f) {w['sf-widget']=o;w[o] = w[o] || function () {(w[o].q = w[o].q || []).push(arguments)};
     js = d.createElement(s);fjs = d.getElementsByTagName(s)[0];js.src = f;js.async = 1;fjs.parentNode.insertBefore(js, fjs);}
     (window, document, 'script', '_sf', 'https://static.searchstax.com/studio-js/v2/js/studio-feedback.js'));
 
     _sf("9irZHJbDKzVGnjJjEGgzOVWLt8e2OAHv6krBuf5uvSY");
   </script>

The parameter to _sf method is the Analytics API Key that is also used before as the connector.apiKey parameter.

Full Example:

For a full example of using the SearchJS module with your own application, visit the Site Search > App Management > Hosted Search App Tab. Enable the Hosted Search App and view it in a browser.

The Hosted Search App is a search page built with the SearchJS Module using your Solr and Site Search settings. Simply view the page source for the most up-to-date example of SearchJS integration.