Skip to content

Page level Metadata

Tiffany Chan edited this page Jun 8, 2020 · 13 revisions

Note: You must have upgraded Universal Viewer to the Hyrax 3 version first.

screenshot of universal viewer

By default, Universal Viewer (UV) shows work-level metadata in the "More Information" panel on the right side. We have changed this to show file set-level or page-level metadata, mainly so that users can view a page's transcription alongside its image. Whenever a user selects or views a different page, the metadata panel refreshes with metadata for the newly selected page.

To include page-level metadata or transcription, simply add it to a CSV for the batch uploader in the "File" row.

Below is an example of a file set's abstract/transcript on its dedicated page, followed by a screenshot of what it looks like in the viewer.

file set transcript

viewer transcript

Developer Notes

A guide to implementing file set or page-level metadata in Universal Viewer.

Overview

  1. Integrate file set metadata into the IIIF manifest used by Universal Viewer (add /manifest.json to the end of a show page link for a work)
  2. Insert event hooks (initial load, when user clicks thumbnail, etc.) (jump here)
  3. Grab the file set ID from the selected thumbnail (jump here)
  4. Make a request to the manifest link using the file set ID (jump here)
  5. Receive and parse the JSON response for the correct page-level metadata (jump here)
  6. Update and populate the metadata panel with that page's information (jump here)

Integrate Page or File Set Metadata into a IIIF Manifest

IIIF supports metadata at the canvas (page) level, but there isn't currently any viewer that will display it, nor does Samvera's IIIF Manifest gem automatically incorporate that metadata into its manifests.

To work around this, we use the IIIF presentation gem to parse the manifest generated by the gem. Once parsed, we query the database for metadata from the work's/manifest's file sets or members. Then we add this metadata to the manifest.

In app/controllers/hyrax/works_controller_behavior.rb#manifest (link):

# Add title and description
resource.label = fs.title.first
resource.description = fs.description.first
# Add other metadata
metadata_labels = fs.attribute_names -
    ["head", "tail", "date_uploaded", "depositor", "date_modified",
    "relative_path", "import_url", "based_near", "access_control_id",
    "embargo_id", "lease_id", "label", "description", "title"] # Don't need these last 3 because they are handled separately
    metadata = metadata_labels.each_with_object([]) do |label_name, array|
        key = label_name.to_s.humanize
        value = fs[label_name].first
        next unless value.present?
        array.push(key => value)
    end

Insert event hooks

For the initial load, we create an event inside public/uv/lib/GalleryComponent.js (link). Insert this around line 57:

//Add event here
var event = new Event('thumbsLoaded');
document.dispatchEvent(event);
console.log("Thumbs loaded");

Then in public/uv/uv.html (link):

          document.addEventListener('thumbsLoaded', function(e) { // See public/uv/lib/iiif-gallery-component.js
             // Delete everything currently in the metadata panel and replace it with our template
             $('.iiif-metadata-component').empty();
             var template = '<div class="groups"><div class="group"><div class="header">About this image</div><div class="items"></div></div></div>';
             $('.iiif-metadata-component').append(template);
             generateMetadata();

In the same file, add other events (link):

             // Refresh the metadata panel if user clicks the thumbnail gallery, arrows, or does an image search
              $('.thumbsView').add('.prevOptions').add('.nextOptions').add('a.go.btn.btn-primary').on('click', function() {
                 generateMetadata();
              });
              // On clicking next or prev arrows in the center panel
              $(document).on('click', '.paging', function(){
                generateMetadata();
              });
              // Or prese enter in the image search bar
              $('.autoCompleteText').keypress(function(event) {
                if (event.keyCode === 13) {
                 generateMetadata();
                }

Make a request to the manifest link

In public/uv/uv.html (inside a script tag):

             // Generate html for file set metadata by making a request to the manifest URL at generic-work/[id]/manifest.json
             function generateMetadata() {
               var manifestUrl = window.location.hash.split('&')[0].replace('#?manifest=', '');
               $.get(manifestUrl, "", success, "json");

Grab the file set ID from the selected thumbnail

In public/uv/uv.html (inside a script tag):

    function success(data) { //if successful ajax request
        //$('.iiif-metadata-component').empty();
        var selected = $('.thumbs').find('.selected'); // the current thumbnail

        if (typeof selected !== 'undefined') {
               var index = parseInt(selected.attr('id').replace('thumb',''));
        } else { // There are no thumbnails because there is only 1 image
               var index = 0;
        }

Receive and parse the JSON response

In public/uv/uv.html (inside a script tag):

         // Grab title, description, and other metadata from the manifest
         var title = data.sequences[0].canvases[index].images[0].resource.label;
         var description = data.sequences[0].canvases[index].images[0].resource.description;
         var metadata = data.sequences[0].canvases[index].images[0].resource.metadata;

            // Dynamically generates a label/value pair for a metadata field (e.g. creator, contributor, etc.)
            // label, value are strings
            function generateItem(label, value) {
              var item = $(document.createElement("div")).addClass("item" + " _" + label.toLowerCase());
              var label = $(document.createElement("div")).addClass("label").text(label);
              var values = $(document.createElement("div")).addClass("values");
              if (label.html() == 'Transcript') {
                  values.html('<div class="value" style="white-space: pre-wrap;">' + value + '</div>');
              } else {
                  values.html('<div class="value">' + value + '</div>');
              }
              item.append(label, values);
              return item;
            }// generateItem()

Update and populate the metadata panel

Create and populate a template with the relevant metadata, then append it to the metadata panel. In public/uv/uv.html (inside a script tag):

            // Dynamically generates a label/value pair for a metadata field (e.g. creator, contributor, etc.)
            // label, value are strings
            function generateItem(label, value) {
              var item = $(document.createElement("div")).addClass("item" + " _" + label.toLowerCase());
              var label = $(document.createElement("div")).addClass("label").text(label);
              var values = $(document.createElement("div")).addClass("values");
              if (label.html() == 'Transcript') {
                  values.html('<div class="value" style="white-space: pre-wrap;">' + value + '</div>');
              } else {
                  values.html('<div class="value">' + value + '</div>');
              }
              item.append(label, values);
              return item;
            }// generateItem()