Skip to content
jabrah edited this page Mar 20, 2017 · 6 revisions

This example will get facet data from a locally deployed JH-IIIF Search service, parse the facet data into an appropriate model for JSTree and populate the tree widget.

Screenshot:

Demo widget

When the web page loads, it makes a request to a locally deployed version of the IIIF Presentation endpoint that includes the faceted search. The request has no search query, but asks for the author facet. In response, the widget receives JSON data that includes an array of facets. Event handlers can be specified to respond to a user interacting with any node. These can be hooked up in a way to send search requests when a user selects a specific value under a category

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

<!-- JSTree dependency -->
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/themes/default/style.min.css" />
  <script src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/jstree.min.js"></script>

  <script src="js/facet.js"></script>
</head>
<body>
<div id="container"></div>

</body>
</html>

js/facet.js

/* jshint esversion:6 */

$(document).ready(function() {
  const FACET_URL = "http://localhost:8080/iiif-pres/collection/top/jhsearch?f=facet_author";
  let model = {
    "core": {
      "data": []
    },
    "plugins": [
      "sort",
      "state",        // Need to check API for configuration
      "wholerow"
    ]
  };

  $.getJSON(FACET_URL)
  .done(function(data) {
    if (!data || !data.facets || !Array.isArray(data.facets) || data.facets.length === 0) {
      console.log("No facets data.");
      return;
    }

    // Add stuff to the UI model
    data.facets.forEach(facet => addFacet(facet));
    $("#container").jstree(model);
    handleEvents();
  });

  /**
   * Setup event handlers for the JSTree object.
   */
  function handleEvents() {
    let cache = [];

    /**
     * Should be used ONLY for debugging
     */
    function skipCircular(key, value) {
      if (typeof value === 'object' && value !== null) {
        if (cache.indexOf(value) !== -1) {
          // Circular reference found, discard key
          return;
        }
        // Store value in our collection
        cache.push(value);
      }
      return value;
    }

    // $("#container").on("activate_node.jstree", function(event, data) {
    //   // console.log("[ActivateNode] " + JSON.stringify(data.node, (k, v) => skipCircular(k, v), 2));
    //   console.log("[ActivateNode] " + JSON.stringify(Object.keys(data)));
    //   _data = data;
    //   cache = [];
    // });

    $("#container").on("select_node.jstree", (event, data) => console.log("[SelectNode] " + JSON.stringify(Object.keys(data))));
  }

  function addFacet(facet) {
    let hasDim = model.core.data.map(el => el.facet_id).includes(facet.dim);
    if (!hasDim) {
      model.core.data.push({
        "facet_id": facet.dim,
        "text": facet.dim,
        "icon": false,
        "children": []
      });
    }

    let node = model.core.data.filter(el => el.facet_id === facet.dim);
    if (node && node.length > 0) {
      add(node[0], facet.path, facet.count);
    }
  }

  function add(node, path, count, index) {
    if (!index) {
      index = 0;
    }

    if (!node.children) {
      node.children = [];
    }

    let child = node.children.filter(c => c.facet_id === path[index]);
    if (child && child.length !== 0) {
      add(child, path, count, index+1);
    } else {
      addPath(node, path, count, index);
    }
  }

  function addPath(node, path, count, index) {
    let toAdd = {
      "facet_id": path[index],
      "text": path[index] + (count > 1 ? " (" + count + ")" : ""),
      "icon": false
    };

    if (!index) {
      index = 0;
    }

    if (Array.isArray(node.children)) {
      node.children.push(toAdd);
    } else {
      node.children = [toAdd];
    }

    if (index === path.length-1) {
      return;   // At target node
    } else {
      addPath(node.children[0], path, count, index+1);
    }
  }
});