ProjectMirador / mirador

An open-source, web-based 'multi-up' viewer that supports zoom-pan-rotate functionality, ability to display/compare simple images, and images with annotations.
https://projectmirador.org
Apache License 2.0
557 stars 256 forks source link

Implement 'List view' of load window plugin #1834

Closed ggeisler closed 5 years ago

ggeisler commented 5 years ago

This is part of #1833.

See the interactive mockup for a better sense of how the plugin is intended to work than I can give with screenshots.

A goal in the design of list view for the load window plugin is to keep the arrangement of resource elements consistent across device sizes, and to use that same arrangement in the sidebar of a collection or multivolume work where we show the manifests that are part of the larger work. For example, here is the proposed arrangement for the window sidebar and the load window on various device sizes:

Window sidebar

window-sidebar-a
window-sidebar-b

Mobile

mobile-list-view

Tablet

At tablet and larger, the device is wide enough to fit all resource elements in the same row:

tablet-list-view

Desktop

desktop-list-view

Linked elements

We don't want to make the entire row linked (because that makes it hard to scroll without selecting a resource on touch devices) but we do want a good-sized link target to make it easy and quick to open a resource. The thumbnail and title are visually grouped and should be a good link target. For accessibility purposes, we should probably group those two elements in HTML and make the group the link (so we don't have repeated links in screenreaders).

General suggestion: The thumbnail and title section takes 100% width on mobile, and 50% width on larger than mobile viewports (leaving the institutional elements the other 50%).

Add resource panel (Split to #1857)

The goal is to enable the user to add a resource via IIIF URL, but to minimize the space an always-present URL input would require. The proposed solution is a button at the bottom that is fixed at the bottom of the viewport. As shown in the screenshots above, in mobile the button just uses an icon but at larger sizes it includes a text label as well.

tablet-add-resource-button

When selected, the add resource panel is displayed (slides up from bottom of viewport):

tablet-add-resource-panel

In terms of Material UI, this is an Expanding bottom sheet. The user can close the panel via the Cancel action or the title bar icon.

When the user clicks Add, a new row is immediately added to the top of the resource list and uses placeholder elements to indicate the resource is actively being retrieved (I couldn't easily do it in the mockup, but ideally the placeholder elements are animated to indicate something is happening. Similar to this example, though I'm not suggesting we use that module in particular.):

tablet-loading-row

If the resource is successfully retrieved, it is added to the list where the placeholder row is (similar to Mirador 2, other than the placeholder elements).

Add resource error message (Split to #1873)

If the resource cannot be retrieved, we should let the user know by replacing the placeholder row with a notification banner. If we follow the Material UI guidelines for the banner, it is displayed at the top of the content area, is non-modal, and pushes content down rather than overlaying it:

tablet-loading-error

(EDIT: @jvine and I discussed and we think we will need to ignore the Material UI guidelines in this case and show the notification banner in place of the placeholder row that failed to load, wherever that placeholder row is in the list. This is because the top-pinned banner placement won't be as intuitive if there are multiple manifest loading errors, or if the manifest that failed to load is not at the top of the list (e.g., on initial load of the list, several manifests fail to load).)

ggeisler commented 5 years ago

Here's a list of manifests from our fixtures page that I've been using locally. Some subset of this list could be used as the plugin's default list of resources, maybe?

          { manifestUri: "http://media.nga.gov/public/manifests/nga_highlights.json", location: "National Gallery of Art"},
          { manifestUri: "https://data.ucd.ie/api/img/manifests/ucdlib:33064", location: "Irish Architectural Archive"},
          { manifestUri: "https://wellcomelibrary.org/iiif/b18035723/manifest", location: "Wellcome Library"},
          { manifestUri: "http://dams.llgc.org.uk/iiif/2.0/4389767/manifest.json", location: "The National Library of Wales"},
          { manifestUri: "https://demos.biblissima.fr/iiif/metadata/florus-dispersus/manifest.json", location: "Biblissima"},
          { manifestUri: "http://beta.biblissima.fr/iiif/manifest/ark:/43093/desc57cb76cd3739a24a9277b6669d95b5f3a590e771", location: "Biblissima"},
          { manifestUri: "https://www.e-codices.unifr.ch/metadata/iiif/gau-Fragment/manifest.json", location: "e-codices - Virtual Manuscript Library of Switzerland"},
          { manifestUri: "https://wellcomelibrary.org/iiif/collection/b18031511", location: "Wellcome Library"},
          { manifestUri: "https://gallica.bnf.fr/iiif/ark:/12148/btv1b10022508f/manifest.json", location: "Bibliothèque nationale de France"},
          { manifestUri: "https://manifests.britishart.yale.edu/Osbornfa1", location: "Beinecke Rare Book and Manuscript Library, Yale University"},
          { manifestUri: "https://iiif.biblissima.fr/chateauroux/B360446201_MS0005/manifest.json", location: "Biblissima"},
          { manifestUri: "https://iiif.durham.ac.uk/manifests/trifle/32150/t1/m4/q7/t1m4q77fr328/manifest", location: "Durham University Library"},
          // { manifestUri: "https://iiif.vam.ac.uk/collections/O1023003/manifest.json", location: "Ocean liners"},
          { manifestUri: "http://storiiies.cogapp.com/holbein/manifest.json", location: "National Gallery, London"}
cbeer commented 5 years ago

@ggeisler: where is that third column of data (organization name?) coming from? I'm not seeing anything entirely appropriate in the IIIF manifests.

Is "X items" the count of canvases in a manifest or manifests in a collection?

ggeisler commented 5 years ago

@cbeer

Is "X items" the count of canvases in a manifest or manifests in a collection?

"items" are canvases. If the manifest represents a collection ("viewingHint": "multi-part",), then my thought was to say "1 collection, x items" where the items in that case are the number of manifests defined in that collection manifest. For an example collection manifest, see https://wellcomelibrary.org/iiif/collection/b18031511. Also, see the very bottom of this mockup for the representation of that manifest in the list:

https://xd.adobe.com/view/477b3833-0ae4-47fa-6032-15d9b7bcd9f0-314a/screen/633e8889-244e-4781-9328-78bdfb635c9d/Tablet-Load-window

In theory, a manifest can be a collection that contains other collections, so that's why I suggest the "1 collection" part. I don't know of a manifest that is a collection of collections to use as an example, though.

where is that third column of data (organization name?) coming from? I'm not seeing anything entirely appropriate in the IIIF manifests.

The list of manifests/collections shown in the load window are intended to be hand-crafted in some way, for example, in the HTML that implements the Mirador instance; that is, someone has to come up with the list of manifest they want to include in the load window for their Mirador implementation. So the institution/attribution label is one that the implementor would directly provide in the code that defines the list, rather than source automatically from the manifest. For example, in my comment above with the list of manifests, I provided two values for each item to be in the list: the manifest URL and the "location" which is the institution/attribution label to be shown in the UI, as in the mockups.

(Some manifests do have an attribution value, which is what I think we'll need to use for the window side panel cases, since those values do need to be pulled directly from the loaded manifest; so that is a difference in the pattern that didn't occur to me until now. But attribution is not always present so I don't think we want to rely on that for the load window presentation.)

For example, here is the source for the Mirador 2 advanced demo, where the load window values for manifest URL and "location/attribution" are manually provided:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <link rel="stylesheet" type="text/css" href="mirador/css/mirador-combined.css">
    <title>Mirador Viewer</title>
    <style type="text/css">
     #viewer {
       width: 100%;
       height: 100%;
       position: fixed;
     }
    </style>
  </head>
  <body>
    <div id="viewer"></div>

    <script src="mirador/mirador.min.js"></script>
    <script type="text/javascript">

     $(function() {
       myMiradorInstance = Mirador({
         id: "viewer",
         layout: "1x1",
         buildPath: "mirador/",
         data: [
           { manifestUri: "https://iiif.lib.harvard.edu/manifests/drs:48309543", location: "Harvard University"},
           { manifestUri: "https://iiif.lib.harvard.edu/manifests/drs:5981093", location: "Harvard University"},
           { manifestUri: "https://iiif.lib.harvard.edu/manifests/via:olvwork576793", location: "Harvard University"},
           { manifestUri: "https://iiif.lib.harvard.edu/manifests/drs:14033171", location: "Harvard University"},
           { manifestUri: "https://iiif.lib.harvard.edu/manifests/drs:46909368", location: "Harvard University"},
           { manifestUri: "https://iiif.lib.harvard.edu/manifests/drs:48331776", location: "Harvard University"},
           { manifestUri: "http://iiif.harvardartmuseums.org/manifests/object/299843", location: "Harvard University"},
           { manifestUri: "http://iiif.harvardartmuseums.org/manifests/object/304136", location: "Harvard University"},
           { manifestUri: "http://iiif.harvardartmuseums.org/manifests/object/198021", location: "Harvard University"},
           { manifestUri: "http://iiif.harvardartmuseums.org/manifests/object/320567", location: "Harvard University"},
           { manifestUri: "https://purl.stanford.edu/qm670kv1873/iiif/manifest.json", location: "Stanford University"},
           { manifestUri: "https://purl.stanford.edu/jr903ng8662/iiif/manifest.json", location: "Stanford University"},
           { manifestUri: "https://purl.stanford.edu/ch264fq0568/iiif/manifest.json", location: "Stanford University"},
           { manifestUri: "https://purl.stanford.edu/wh234bz9013/iiif/manifest.json", location: "Stanford University"},
           { manifestUri: "https://purl.stanford.edu/rd447dz7630/iiif/manifest.json", location: "Stanford University"},
           { manifestUri: "http://dms-data.stanford.edu/data/manifests/Stanford/ege1/manifest.json", location: "Stanford University"},
           { manifestUri: "http://dams.llgc.org.uk/iiif/4574752/manifest.json", location: "National Library of Wales"},
           { manifestUri: "http://dev.llgc.org.uk/iiif/ww1posters.json", location: "National Library of Wales"},
           { manifestUri: "http://dams.llgc.org.uk/iiif/newspaper/issue/3320640/manifest.json", location: "National Library of Wales"},
           { manifestUri: "http://dams.llgc.org.uk/iiif/2.0/1465298/manifest.json", location: "National Library of Wales"},
           { manifestUri: "http://manifests.ydc2.yale.edu/manifest/Admont23", location: "Yale University"},
           { manifestUri: "http://manifests.ydc2.yale.edu/manifest/Admont43", location: "Yale University"},
           { manifestUri: "http://manifests.ydc2.yale.edu/manifest/BeineckeMS10", location: "Yale University"},
           { manifestUri: "http://manifests.britishart.yale.edu/manifest/5005", location: "Yale Center For British Art"},
           { manifestUri: "http://manifests.britishart.yale.edu/manifest/1474", location: "Yale Center For British Art"},
           { manifestUri: "http://iiif.bodleian.ox.ac.uk/iiif/manifest/51a65464-6408-4a78-9fd1-93e1fa995b9c.json", location: "Bodleian Libraries"},
           { manifestUri: "http://iiif.bodleian.ox.ac.uk/iiif/manifest/f19aeaf9-5aba-4cee-be32-584663ff1ef1.json", location: "Bodleian Libraries"},
           { manifestUri: "http://iiif.bodleian.ox.ac.uk/iiif/manifest/3b31c0a9-3dab-4801-b3dc-f2a3e3786d34.json", location: "Bodleian Libraries"},
           { manifestUri: "http://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json", location: "Bodleian Libraries"},
           { manifestUri: "http://gallica.bnf.fr/iiif/ark:/12148/btv1b84539771/manifest.json", location: 'BnF'},
           { manifestUri: "http://gallica.bnf.fr/iiif/ark:/12148/btv1b10500687r/manifest.json", location: 'BnF'},
           { manifestUri: "http://gallica.bnf.fr/iiif/ark:/12148/btv1b55002605w/manifest.json", location: 'BnF'},
           { manifestUri: "http://gallica.bnf.fr/iiif/ark:/12148/btv1b55002481n/manifest.json", location: 'BnF'},
           { manifestUri: "http://www.e-codices.unifr.ch/metadata/iiif/sl-0002/manifest.json", location: 'e-codices'},
           { manifestUri: "http://www.e-codices.unifr.ch/metadata/iiif/bge-cl0015/manifest.json", location: 'e-codices'},
           { manifestUri: "http://www.e-codices.unifr.ch/metadata/iiif/fmb-cb-0600a/manifest.json", location: 'e-codices'},
           { manifestUri: "https://data.ucd.ie/api/img/manifests/ucdlib:33064", location: "University College Dublin"},
           { manifestUri: "https://data.ucd.ie/api/img/manifests/ucdlib:40851", location: "University College Dublin"},
           { manifestUri: "https://data.ucd.ie/api/img/manifests/ucdlib:30708", location: "University College Dublin"},
           { manifestUri: "http://dzkimgs.l.u-tokyo.ac.jp/iiif/zuzoubu/12b02/manifest.json", location: "University of Tokyo"},
           { manifestUri: "http://www2.dhii.jp/nijl/NIJL0018/099-0014/manifest_tags.json", location: "NIJL"},
           { manifestUri: "http://digi.vatlib.it/iiif/MSS_Vat.lat.3225/manifest.json", location: "Vatican Library"},
           { manifestUri: "http://media.nga.gov/public/manifests/nga_highlights.json", location: "National Gallery of Art"}
         ],
         windowObjects: [],
         annotationEndpoint: {
           name:"Local Storage",
           module: "LocalStorageEndpoint" }
       });
     });
    </script>
  </body>
</html>

I'm not sure how this translates to creating the load window as a plugin, though. I don't understand the technical details about instantiating Mirador and how plugins fit in, etc. But my assumption was that a human will need to provide the list of manifest URLs to be in the load window list, and they would also provide the "location/attribution" label in a way similar to above.

cbeer commented 5 years ago

with the list of manifest they want to include in the load window for their Mirador implementation.

How does that work with manifests added with the Add resource button?

ggeisler commented 5 years ago

Yeah, good question. I think we should do the same thing as you see in the Mirador 2 demo when you add from a URL. Instead of the location/attribution label, they show "(Added from URL)".

For example, at http://projectmirador.org/demo/ add this URL: https://iiif.durham.ac.uk/manifests/trifle/32150/t1/m4/q7/t1m4q77fr328/manifest

(I'd like to say we should use the attribution value from the manifest if one exists, but I've seen many examples that are very long and not really appropriate for the load window display.)

cbeer commented 5 years ago

Is that, perhaps, IIIF spec enhancement feedback we should provide to @mikeapp?

ggeisler commented 5 years ago

Like suggesting a new property that is intended for scenarios like the load window, where the purpose is a short representation of the institution or source location of the manifest?

mikeapp commented 5 years ago

The new-in-3.0-beta provider might be a way to handle this, https://preview.iiif.io/api/image-prezi-rc2/api/presentation/3.0/#provider , you can get the data from the Manifest. The provider(s) also encapsulate the homepage and logo, which the client might need for its UI.

If you absolutely need to be able to configure this in the page itself then perhaps targeting a subset of the properties found in the full manifest, e.g.:

 data:
[
  {  id:"https://....", provider: [ { label: { en: "Yale University" } } ] }
]

(But if you're supplying a provider label that isn't in the manifest, this might be misleading...)

If you go with a custom pattern for this you'll want to consider internationalization via a language map.

ggeisler commented 5 years ago

Thanks for the pointer @mikeapp. provider looks like a great addition to the spec.