Upgrading a template with a default sessions and history widget

This upgrade guide documents the steps required to upgrade a template for an existing built search that used the default session search and click history or the session cart tools widgets.

This guide provides the steps required to update a template that includes an un-customized sessions and history widget. If you are using a template that also customizes the sessions and history widget please see: upgrading a template with a customized sessions and history widget.

Upgrade path

The upgrade process involves two steps: replacing JavaScript libraries and updating Freemarker templates.

The specifics of each step depend on the upgrade path, however. Follow the procedure for the upgrade path being taken.

Upgrade from Funnelback 15 to Funnelback 16

Replace JavaScript libraries

Prior to Funnelback 15.24, the widget was delivered using an angularJS based session library. As of Funnelback 15.24, this was split into two independent widgets; one to handle search and click history and another to handle cart functionality.

Because of this the funnelback-session-1.0.0.js library uses AngularJS. It has been superseded by newer libraries using Handlebars. funnelback-session-1.0.0.js should be removed.

Regarding upgrading from Funnelback 15
  1. The example below assumes the Funnelback Session JavaScript library includes the version number in the file-name. In some older iterations, however, this library did not append the version number: the file was named funnelback-session.js.

    The example below assumes the library filename includes the version number.

  2. The AngularJS library was previously used only for the Funnelback session tool, and, as noted above, it should also be removed.

    It is possible, however, for custom functionality relying on this library to be added to a customized template. If that is the case, the AngularJS library should not be removed.

    The example below assumes the AngularJS library is removed.

Replace:

<script src="${GlobalResourcesPrefix}thirdparty/angular-1.0.7/angular.js"></script>
<script src="${GlobalResourcesPrefix}thirdparty/angular-1.0.7/angular-resource.js"></script>
<script src="${GlobalResourcesPrefix}js/funnelback-session-1.0.0.js"></script>

with:

<script nomodule type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/es6-promise-4.2.5/es6-promise.auto.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/handlebars-4.7/handlebars.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-cart-0.1.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-history-0.1.min.js"></script>

<script type="text/javascript">
  var flbSessionCart = new Funnelback.SessionCart({collection: '${question.collection.id}'});
  var flbSessionHistory = new Funnelback.SessionHistory({collection: '${question.collection.id}'});
</script>

Update Freemarker templates

Update the code within existing Funnelback Freemarker templates to make use of the two replacement widgets.

  1. From the <style> tag located in the <head> section, remove the following angularJS specific classes:

    [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; }
  2. From the <body> tag, remove the attributes that were previously used to initiate the angularJS library.

    Replace:

    <body<#if question.collection.configuration.valueAsBoolean("ui.modern.session")> data-ng-app="Funnelback" data-ng-controller="DefaultCtrl"</#if>>

    with:

    <body>
  3. Update the element used to trigger the display of the cart.

    Replace:

    <li data-ng-class="{active: isDisplayed('cart')}"><a href="#" data-ng-click="toggleCart()" title="{{cart.length}} item(s) in your selection"><span class="glyphicon glyphicon-shopping-cart"></span> <span class="badge" data-ng-cloak>{{cart.length}}</ng-pluralize --></span></a></li>

    with:

    <li class="flb-cart-count"></li>
  4. Update the element used to trigger the display of the history box.

    Replace:

    <li data-ng-class="{active: isDisplayed('history')}"><a href="#"  data-ng-click="toggleHistory()" title="Search History">History</a></li>

    with:

    <li><a class="session-history-toggle">History</a></li>
  5. Remove the angularJS attribute and instead add an id attribute with search-results-content.

    Replace:

    <div class="row" data-ng-show="isDisplayed('results')">

    with:

    <div id="search-results-content" class="row">
  6. Remove angularJS attributes that are no longer used.

    Replace:

    <div class="breadcrumb" data-ng-controller="SearchHistoryCtrl" data-ng-show="!searchHistoryEmpty">

    with:

    <div class="breadcrumb session-history-breadcrumb">
  7. Remove angularJS attributes that were used to show the history box and instead add the CSS class session-history-show.

    Replace:

    <button class="btn btn-link pull-right" data-ng-click="toggleHistory()"><small class="text-muted"><span class="glyphicon glyphicon-plus"></span> More&hellip;</small></button>

    with:

    <button class="btn btn-link pull-right session-history-show"><small class="text-muted"><span class="glyphicon glyphicon-plus"></span> More&hellip;</small></button>
  8. Remove the code below as the cart widget now handles the display of adding or removing items from the cart.

    <#if question.collection.configuration.valueAsBoolean("ui.modern.session")><a href="#" data-ng-click="toggle()" data-cart-link data-css="pushpin|remove" title="{{label}}"><small class="glyphicon glyphicon-{{css}}"></small></a></#if>
  9. Remove the angularJS attribute previously used to show the history box and instead add the CSS class session-history-show. Optionally add the class session-history-link as well so that this link will be hidden if the click history is cleared.

    Replace:

    <small class="text-warning"><span class="glyphicon glyphicon-time"></span> <a title="Click history" href="#" class="text-warning" data-ng-click="toggleHistory()">Last visited ${prettyTime(session.getClickHistory(s.result.indexUrl).clickDate)}</a></small>

    with:

    <small class="text-warning session-history-link"><span class="glyphicon glyphicon-time"></span> <a title="Click history" href="#" class="text-warning session-history-show">Last visited ${prettyTime(session.getClickHistory(s.result.indexUrl).clickDate)}</a></small>
  10. Remove the angularJS attributes.

    Replace:

    <div id="search-history" data-ng-cloak data-ng-show="isDisplayed('history')">

    with:

    <div id="search-history">
  11. Remove the angularJS attributes previously used to disable the query box when result cart or session history was open. This is no longer necessary to disable.

    Replace:

    <div class="form-group">
      <input required name="query" id="query" title="Search query" type="text" value="${question.inputParameterMap["query"]!}" accesskey="q" placeholder="Search <@s.cfg>service_name</@s.cfg>&hellip;" class="form-control query" data-ng-disabled="isDisplayed('cart') || isDisplayed('history')">
    </div>
    <button type="submit" class="btn btn-primary" data-ng-disabled="isDisplayed('cart') || isDisplayed('history')"><span class="glyphicon glyphicon-search"></span> Search</button>

    with:

    <div class="form-group">
      <input required name="query" id="query" title="Search query" type="text" value="${question.inputParameters["query"]?first!}" accesskey="q" placeholder="Search <@s.cfg>service_name</@s.cfg>&hellip;" class="form-control query">
    </div>
    <button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-search"></span> Search</button>
  12. Remove the angularJS attribute previously used to hide the history box and instead add the CSS class session-history-hide.

    Replace:

    <a href="#" data-ng-click="hideHistory()"><span class="glyphicon glyphicon-arrow-left"></span> Back to results</a>

    with:

    <a href="#" class="session-history-hide"><span class="glyphicon glyphicon-arrow-left"></span> Back to results</a>
  13. Update the output of the click history data.

    Replace:

    <div class="col-md-6" data-ng-controller="ClickHistoryCtrl">
      <div data-ng-show="!clickHistoryEmpty && <@fb.HasClickHistory />">
        <h3><span class="glyphicon glyphicon-heart"></span> Recently clicked results
          <button class="btn btn-danger btn-xs" title="Clear click history" data-ng-click="clear('Your history will be cleared')"><span class="glyphicon glyphicon-remove"></span> Clear</button>
        </h3>
        <ul class="list-unstyled">
          <#list session.clickHistory as h>
            <li><a href="${h.indexUrl}">${h.title}</a> &middot; <span class="text-warning">${prettyTime(h.clickDate)}</span><#if h.query??><span class="text-muted"> for &quot;${h.query!}&quot;</#if></span></li>
          </#list>
        </ul>
      </div>
      <div data-ng-show="clickHistoryEmpty || !<@fb.HasClickHistory />">
        <h3><span class="glyphicon glyphicon-heart"></span> Recently clicked results</h3>
        <p class="text-muted">Your click history is empty.</p>
      </div>
    </div>

    with:

    <div class="col-md-6">
      <h3>
        <span class="glyphicon glyphicon-heart"></span> Recently clicked results
        <button class="btn btn-danger btn-xs session-history-clear-click" title="Clear click history"><span class="glyphicon glyphicon-remove"></span> Clear</button>
      </h3>
      <#list session.clickHistory>
        <ul class="session-history-click-results">
        <#items as h>
          <li><a href="${h.indexUrl}">${h.title}</a> &middot; <span class="text-warning">${prettyTime(h.clickDate)}</span><#if h.query??><span class="text-muted"> for &quot;${h.query!}&quot;</#if></span></li>
        </#items>
        </ul>
      </#list>
      <p class="session-history-click-empty text-muted">Your click history is empty.</p>
    </div>
  14. Update the output of the search history data.

    Replace:

    <div class="col-md-6" data-ng-controller="SearchHistoryCtrl">
      <div data-ng-show="!searchHistoryEmpty && <@fb.HasSearchHistory />">
        <h3><span class="glyphicon glyphicon-search"></span> Recent searches
          <button class="btn btn-danger btn-xs" title="Clear search history" data-ng-click="clear('Your history will be cleared')"><span class="glyphicon glyphicon-remove"></span> Clear</button>
        </h3>
        <ul class="list-unstyled">
          <#list session.searchHistory as h>
            <li><a href="?${h.searchParams}">${h.originalQuery!} <small>(${h.totalMatching})</small></a> &middot; <span class="text-warning">${prettyTime(h.searchDate)}</span></li>
          </#list>
        </ul>
      </div>
      <div data-ng-show="searchHistoryEmpty || !<@fb.HasSearchHistory />">
        <h3><span class="glyphicon glyphicon-search"></span> Recent searches</h3>
        <p class="text-muted">Your search history is empty.</p>
      </div>
    </div>

    with:

    <div class="col-md-6">
      <h3>
        <span class="glyphicon glyphicon-search"></span> Recent searches
        <button class="btn btn-danger btn-xs session-history-clear-search" title="Clear search history"><span class="glyphicon glyphicon-remove"></span> Clear</button>
      </h3>
      <#list session.searchHistory>
        <ul class="session-history-search-results list-unstyled">
        <#items as h>
          <li><a href="?${h.searchParams}">${h.originalQuery!} <small>(${h.totalMatching})</small></a> &middot; <span class="text-warning">${prettyTime(h.searchDate)}</span></li>
        </#items>
        </ul>
      </#list>
      <p class="session-history-search-empty text-muted">Your search history is empty.</p>
    </div>
  15. Update the output of cart data. The cart data display is now handled by widget using Handlebars templating.

    Replace:

    <div id="search-cart" data-ng-cloak data-ng-show="isDisplayed('cart')" data-ng-controller="CartCtrl">
      <div class="row">
        <div class="col-md-12">
          <a href="#" data-ng-click="hideCart()"><span class="glyphicon glyphicon-arrow-left"></span> Back to results</a>
          <h2><span class="glyphicon glyphicon-pushpin"></span> Saved
            <button class="btn btn-danger btn-xs" title="Clear selection" data-ng-click="clear('Your selection will be cleared')"><span class="glyphicon glyphicon-remove"></span> Clear</button>
          </h2>
    
          <ul class="list-unstyled">
            <li data-ng-repeat="item in cart">
              <h4>
                <a title="Remove" data-ng-click="remove(item.indexUrl)" href="javascript:;"><small class="glyphicon glyphicon-remove"></small></a>
                <a href="{{item.indexUrl}}">{{item.title|truncate:70}}</a>
              </h4>
    
              <cite class="text-success">{{item.indexUrl|cut:'http://'}}</cite>
              <p>{{item.summary|truncate:255}}</p>
            </li>
          </ul>
        </div>
      </div>
    </div>

    with:

    <div id="search-cart"></div>

Upgrade from Funnelback 15 to Funnelback DXP

Replace JavaScript libraries

Prior to Funnelback 15.24, the widget was delivered using an angularJS based session library. As of Funnelback 15.24, this was split into two independent widgets; one to handle search and click history and another to handle cart functionality.

Because of this the funnelback-session-1.0.0.js library uses AngularJS. It has been superseded by newer libraries using Handlebars. funnelback-session-1.0.0.js should be removed.

Regarding upgrading from Funnelback 15
  1. The example below assumes the Funnelback Session JavaScript library includes the version number in the file-name. In some older iterations, however, this library did not append the version number: the file was named funnelback-session.js.

    The example below assumes the library filename includes the version number.

  2. The AngularJS library was previously used only for the Funnelback session tool, and, as noted above, it should also be removed.

    It is possible, however, for custom functionality relying on this library to be added to a customized template. If that is the case, the AngularJS library should not be removed.

    The example below assumes the AngularJS library is removed.

Replace JavaScript Libraries

Replace:

<script src="${GlobalResourcesPrefix}thirdparty/angular-1.0.7/angular.js"></script>
<script src="${GlobalResourcesPrefix}thirdparty/angular-1.0.7/angular-resource.js"></script>
<script src="${GlobalResourcesPrefix}js/funnelback-session-1.0.0.js"></script>

with:

<script nomodule type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/es6-promise-4.2.5/es6-promise.auto.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/handlebars-4.7/handlebars.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-cart-1.0.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-history-1.0.min.js"></script>

<script type="text/javascript">
  var flbSessionCart = new Funnelback.SessionCart({collection: '${question.collection.id}'});
  var flbSessionHistory = new Funnelback.SessionHistory({collection: '${question.collection.id}'});
</script>

Update Freemarker templates

Make the following changes to simple.ftl.

  1. Replace the recent Session history block with a <div id="search-history-recent"> div.

    That is replace

              <#-- Build list of previous queries -->
    
              <#assign qsSignature = computeQueryStringSignature(QueryString) />
              <#if session.searchHistory?? && (session.searchHistory?size gt 1 || session.searchHistory[0].searchParamsSignature != qsSignature)>
                <div class="breadcrumb session-history-breadcrumb">
                  <button class="btn btn-link pull-right session-history-show"><small class="text-muted"><span class="glyphicon glyphicon-plus"></span> More&hellip;</small></button>
                  <ol class="list-inline" >
                    <li class="text-muted">Recent:</li>
                    <#list session.searchHistory as h>
                      <#if h.searchParamsSignature != qsSignature>
                        <#outputformat "plainText">
                        <#assign facetDescription><#compress>
                        <#list h.searchParams?matches("f\\.([^=]+)=([^&]+)") as f>
                            ${urlDecode(f?groups[1])?split("|")[0]} = ${urlDecode(f?groups[2])}<#if f_has_next><br></#if>
                        </#list>
                        </#compress></#assign>
                        </#outputformat>
                        <li>
                          <a <#if facetDescription != ""> data-toggle="tooltip" data-placement="bottom" title="${facetDescription}"</#if> title="${prettyTime(h.searchDate)}" href="${question.currentProfileConfig.get("ui.modern.search_link")}?${h.searchParams}">${h.originalQuery!} <small>(${h.totalMatching})</small></a>
                          <#if facetDescription != ""><i class="glyphicon glyphicon-filter"></i></a></#if>
                        </li>
                      </#if>
                    </#list>
                  </ol>
                </div>
              </#if>

    with

    <div id="search-history-recent"></div>
  2. Replace the Session history block with a <div id="search-history"> div.

    That is replace

          <div id="search-history">
            <div class="row">
              <div class="col-md-12">
                <a href="#" class="session-history-hide"><span class="glyphicon glyphicon-arrow-left"></span> Back to results</a>
                <h2><span class="glyphicon glyphicon-time"></span> History</h2>
    
                <div class="row">
                  <div class="col-md-6">
      <h3>
        <span class="glyphicon glyphicon-heart"></span> Recently clicked results
        <button class="btn btn-danger btn-xs session-history-clear-click" title="Clear click history"><span class="glyphicon glyphicon-remove"></span> Clear</button>
      </h3>
      <#list session.clickHistory>
        <ul class="session-history-click-results">
        <#items as h>
          <li><a href="${h.indexUrl}">${h.title}</a> &middot; <span class="text-warning">${prettyTime(h.clickDate)}</span><#if h.query??><span class="text-muted"> for &quot;${h.query!}&quot;</#if></span></li>
        </#items>
        </ul>
      </#list>
      <p class="session-history-click-empty text-muted">Your click history is empty.</p>
    </div>
                  <div class="col-md-6">
      <h3>
        <span class="glyphicon glyphicon-search"></span> Recent searches
        <button class="btn btn-danger btn-xs session-history-clear-search" title="Clear search history"><span class="glyphicon glyphicon-remove"></span> Clear</button>
      </h3>
      <#list session.searchHistory>
        <ul class="session-history-search-results list-unstyled">
        <#items as h>
          <li><a href="?${h.searchParams}">${h.originalQuery!} <small>(${h.totalMatching})</small></a> &middot; <span class="text-warning">${prettyTime(h.searchDate)}</span></li>
        </#items>
        </ul>
      </#list>
      <p class="session-history-search-empty text-muted">Your search history is empty.</p>
    </div>
                </div>
              </div>
            </div>
          </div>

    with

    <div id="search-history"></div>
  3. Finally, in the Last visited time display block, remove this line:

    <#if question.currentProfileConfig.get("ui.modern.session")?boolean && session?? && session.getClickHistory(s.result.indexUrl)??><small class="text-warning session-history-link"><span class="glyphicon glyphicon-time"></span> <a title="Click history" href="#" class="text-warning session-history-show">Last visited ${prettyTime(session.getClickHistory(s.result.indexUrl).clickDate)}</a></small></#if>

Upgrade from Funnelback 16 to Funnelback DXP

Replace JavaScript Libraries

Replace:

<script nomodule type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/es6-promise-4.2.5/es6-promise.auto.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/handlebars-4.7/handlebars.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-cart-0.1.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-history-0.1.min.js"></script>

<script type="text/javascript">
  var flbSessionCart = new Funnelback.SessionCart({collection: '${question.collection.id}'});
  var flbSessionHistory = new Funnelback.SessionHistory({collection: '${question.collection.id}'});
</script>

with:

<script nomodule type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/es6-promise-4.2.5/es6-promise.auto.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}thirdparty/handlebars-4.7/handlebars.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-cart-1.0.min.js"></script>
<script type="text/javascript" src="${GlobalResourcesPrefix}js/funnelback.session-history-1.0.min.js"></script>

<script type="text/javascript">
  var flbSessionCart = new Funnelback.SessionCart({collection: '${question.collection.id}'});
  var flbSessionHistory = new Funnelback.SessionHistory({collection: '${question.collection.id}'});
</script>

Update Freemarker templates

Make the following changes to simple.ftl.

  1. Replace the recent Session history block with a <div id="search-history-recent"> div.

    That is replace

              <#-- Build list of previous queries -->
    
              <#assign qsSignature = computeQueryStringSignature(QueryString) />
              <#if session.searchHistory?? && (session.searchHistory?size gt 1 || session.searchHistory[0].searchParamsSignature != qsSignature)>
                <div class="breadcrumb session-history-breadcrumb">
                  <button class="btn btn-link pull-right session-history-show"><small class="text-muted"><span class="glyphicon glyphicon-plus"></span> More&hellip;</small></button>
                  <ol class="list-inline" >
                    <li class="text-muted">Recent:</li>
                    <#list session.searchHistory as h>
                      <#if h.searchParamsSignature != qsSignature>
                        <#outputformat "plainText">
                        <#assign facetDescription><#compress>
                        <#list h.searchParams?matches("f\\.([^=]+)=([^&]+)") as f>
                            ${urlDecode(f?groups[1])?split("|")[0]} = ${urlDecode(f?groups[2])}<#if f_has_next><br></#if>
                        </#list>
                        </#compress></#assign>
                        </#outputformat>
                        <li>
                          <a <#if facetDescription != ""> data-toggle="tooltip" data-placement="bottom" title="${facetDescription}"</#if> title="${prettyTime(h.searchDate)}" href="${question.currentProfileConfig.get("ui.modern.search_link")}?${h.searchParams}">${h.originalQuery!} <small>(${h.totalMatching})</small></a>
                          <#if facetDescription != ""><i class="glyphicon glyphicon-filter"></i></a></#if>
                        </li>
                      </#if>
                    </#list>
                  </ol>
                </div>
              </#if>

    with

    <div id="search-history-recent"></div>
  2. Replace the Session history block with a <div id="search-history"> div.

    That is replace

          <div id="search-history">
            <div class="row">
              <div class="col-md-12">
                <a href="#" class="session-history-hide"><span class="glyphicon glyphicon-arrow-left"></span> Back to results</a>
                <h2><span class="glyphicon glyphicon-time"></span> History</h2>
    
                <div class="row">
                  <div class="col-md-6">
      <h3>
        <span class="glyphicon glyphicon-heart"></span> Recently clicked results
        <button class="btn btn-danger btn-xs session-history-clear-click" title="Clear click history"><span class="glyphicon glyphicon-remove"></span> Clear</button>
      </h3>
      <#list session.clickHistory>
        <ul class="session-history-click-results">
        <#items as h>
          <li><a href="${h.indexUrl}">${h.title}</a> &middot; <span class="text-warning">${prettyTime(h.clickDate)}</span><#if h.query??><span class="text-muted"> for &quot;${h.query!}&quot;</#if></span></li>
        </#items>
        </ul>
      </#list>
      <p class="session-history-click-empty text-muted">Your click history is empty.</p>
    </div>
                  <div class="col-md-6">
      <h3>
        <span class="glyphicon glyphicon-search"></span> Recent searches
        <button class="btn btn-danger btn-xs session-history-clear-search" title="Clear search history"><span class="glyphicon glyphicon-remove"></span> Clear</button>
      </h3>
      <#list session.searchHistory>
        <ul class="session-history-search-results list-unstyled">
        <#items as h>
          <li><a href="?${h.searchParams}">${h.originalQuery!} <small>(${h.totalMatching})</small></a> &middot; <span class="text-warning">${prettyTime(h.searchDate)}</span></li>
        </#items>
        </ul>
      </#list>
      <p class="session-history-search-empty text-muted">Your search history is empty.</p>
    </div>
                </div>
              </div>
            </div>
          </div>

    with

    <div id="search-history"></div>
  3. Finally, in the Last visited time display block, remove this line:

    <#if question.currentProfileConfig.get("ui.modern.session")?boolean && session?? && session.getClickHistory(s.result.indexUrl)??><small class="text-warning session-history-link"><span class="glyphicon glyphicon-time"></span> <a title="Click history" href="#" class="text-warning session-history-show">Last visited ${prettyTime(session.getClickHistory(s.result.indexUrl).clickDate)}</a></small></#if>