├── .gitignore
├── IiifItemsPlugin.php
├── LICENSE
├── README.md
├── config_form.php
├── controllers
├── AnnotationController.php
├── AnnotatorController.php
├── CollectionsController.php
├── ImportController.php
├── ManifestController.php
├── MiradorController.php
└── SearchController.php
├── helpers
└── IiifItemsFunctions.php
├── languages
├── en.mo
├── en.po
├── fr.mo
├── fr.po
├── special_strings.php
├── template.pot
├── zh_CN.mo
├── zh_CN.po
├── zh_TW.mo
└── zh_TW.po
├── libraries
└── IiifItems
│ ├── BaseController.php
│ ├── BaseIntegration.php
│ ├── BaseMigration.php
│ ├── Form
│ ├── Config.php
│ └── Import.php
│ ├── IiifUtil.php
│ ├── ImageDownloader.php
│ ├── Integration
│ ├── Annotations.php
│ ├── Collections.php
│ ├── ExhibitBuilder.php
│ ├── Files.php
│ ├── Items.php
│ ├── Search.php
│ ├── SimplePages.php
│ └── System.php
│ ├── Job
│ ├── AddAnnotationThumbnail.php
│ ├── AddUuid.php
│ ├── Import.php
│ └── RemoveSubannotations.php
│ ├── Migration
│ ├── 0_0_1.php
│ ├── 0_0_1_1.php
│ ├── 0_0_1_10.php
│ ├── 0_0_1_11.php
│ ├── 0_0_1_3.php
│ ├── 0_0_1_4.php
│ ├── 0_0_1_5.php
│ ├── 0_0_1_6.php
│ ├── 0_0_1_7.php
│ ├── 0_0_1_8.php
│ ├── 0_0_1_9.php
│ ├── 1_0_1_1_Unification.php
│ └── 1_0_1_2_View_Options.php
│ └── Util
│ ├── Annotation.php
│ ├── Canvas.php
│ ├── Collection.php
│ ├── CollectionOptions.php
│ ├── Manifest.php
│ └── Search.php
├── models
├── IiifItems
│ ├── CachedJsonData.php
│ └── JobStatus.php
└── Table
│ └── IiifItems
│ ├── CachedJsonData.php
│ └── JobStatus.php
├── options.ini.example
├── placeholders
├── iiifitems_audio.jpg
├── iiifitems_file.jpg
├── iiifitems_image.jpg
├── iiifitems_mixed.jpg
├── iiifitems_none.jpg
├── iiifitems_pdf.jpg
├── iiifitems_text.jpg
├── iiifitems_video.jpg
└── iiifitems_zip.jpg
├── plugin.ini
├── routes.ini
└── views
├── admin
├── annotator
│ └── annotate.php
├── collections
│ ├── explorer.php
│ ├── members.php
│ └── tree.php
├── import
│ ├── _nav.php
│ ├── form.php
│ ├── maintenance.php
│ └── status.php
└── mirador
│ └── annotator.php
├── public
├── collections
│ ├── explorer.php
│ └── tree.php
└── mirador
│ ├── multiviewer.php
│ ├── neatline.php
│ └── viewer.php
└── shared
├── exhibit_layouts
├── iiifitem
│ ├── form.php
│ ├── layout.css
│ ├── layout.php
│ └── layout.png
└── iiifmanifest
│ ├── form.php
│ ├── layout.css
│ ├── layout.php
│ └── layout.png
├── img
└── icon_collection.png
└── js
├── iiif-explorer-component
├── css
│ └── iiif-explorer-component.css
├── img
│ ├── folder-closed.png
│ ├── folder-open.png
│ └── resource.png
└── js
│ ├── base-component.bundle.js
│ ├── iiif-explorer-component.js
│ └── manifold.bundle.js
├── mirador
├── ZeroClipboard.swf
├── css
│ └── mirador-combined.css
├── fonts
│ ├── FontAwesome.otf
│ ├── MaterialIcons-Regular.eot
│ ├── MaterialIcons-Regular.ijmap
│ ├── MaterialIcons-Regular.svg
│ ├── MaterialIcons-Regular.ttf
│ ├── MaterialIcons-Regular.woff
│ ├── MaterialIcons-Regular.woff2
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── images
│ ├── border_type_1.png
│ ├── border_type_2.png
│ ├── border_type_3.png
│ ├── border_type_4.png
│ ├── border_type_5.png
│ ├── debut_dark.png
│ ├── jstree
│ │ ├── 32px.png
│ │ ├── 40px.png
│ │ └── throbber.gif
│ └── palette_icon.png
├── locales
│ ├── ar
│ │ └── translation.json
│ ├── de
│ │ └── translation.json
│ ├── en
│ │ └── translation.json
│ ├── es
│ │ └── translation.json
│ ├── fr
│ │ └── translation.json
│ ├── ga
│ │ └── translation.json
│ ├── ja
│ │ └── translation.json
│ ├── ko
│ │ └── translation.json
│ ├── nl
│ │ └── translation.json
│ ├── zh-CN
│ │ └── translation.json
│ ├── zh-TW
│ │ └── translation.json
│ └── zh
│ │ └── translation.json
├── mirador.js
├── plugins
│ ├── advlist
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── anchor
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── autolink
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── autoresize
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── autosave
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── bbcode
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── charmap
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── code
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── codesample
│ │ ├── css
│ │ │ └── prism.css
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── colorpicker
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── contextmenu
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── directionality
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── emoticons
│ │ ├── img
│ │ │ ├── smiley-cool.gif
│ │ │ ├── smiley-cry.gif
│ │ │ ├── smiley-embarassed.gif
│ │ │ ├── smiley-foot-in-mouth.gif
│ │ │ ├── smiley-frown.gif
│ │ │ ├── smiley-innocent.gif
│ │ │ ├── smiley-kiss.gif
│ │ │ ├── smiley-laughing.gif
│ │ │ ├── smiley-money-mouth.gif
│ │ │ ├── smiley-sealed.gif
│ │ │ ├── smiley-smile.gif
│ │ │ ├── smiley-surprised.gif
│ │ │ ├── smiley-tongue-out.gif
│ │ │ ├── smiley-undecided.gif
│ │ │ ├── smiley-wink.gif
│ │ │ └── smiley-yell.gif
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── fullpage
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── fullscreen
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── hr
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── image
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── imagetools
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── importcss
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── insertdatetime
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── layer
│ │ ├── index.js
│ │ └── plugin.min.js
│ ├── legacyoutput
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── link
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── lists
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── media
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── nonbreaking
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── noneditable
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── pagebreak
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── paste
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── preview
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── print
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── save
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── searchreplace
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── spellchecker
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── tabfocus
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── table
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── template
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── textcolor
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── textpattern
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── toc
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── visualblocks
│ │ ├── css
│ │ │ └── visualblocks.css
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ ├── visualchars
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
│ └── wordcount
│ │ ├── index.js
│ │ ├── plugin.js
│ │ └── plugin.min.js
├── skins
│ └── lightgray
│ │ ├── content.inline.min.css
│ │ ├── content.min.css
│ │ ├── fonts
│ │ ├── tinymce-small.eot
│ │ ├── tinymce-small.svg
│ │ ├── tinymce-small.ttf
│ │ ├── tinymce-small.woff
│ │ ├── tinymce.eot
│ │ ├── tinymce.svg
│ │ ├── tinymce.ttf
│ │ └── tinymce.woff
│ │ ├── img
│ │ ├── anchor.gif
│ │ ├── loader.gif
│ │ ├── object.gif
│ │ └── trans.gif
│ │ ├── skin.ie7.min.css
│ │ └── skin.min.css
└── themes
│ ├── inlite
│ ├── index.js
│ ├── theme.js
│ └── theme.min.js
│ └── modern
│ ├── index.js
│ ├── theme.js
│ └── theme.min.js
├── mirador_endpoint.js
└── omeka_tinymce.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /options.ini
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IIIF Toolkit
2 |
3 | Annotate. Present. Impress.
4 |
5 | IIIF Toolkit by University of Toronto Libraries is a plugin for Omeka Classic 2.3 and up. It integrates Mirador with a built-in annotator, a manifest generator, Simple Pages shortcodes and Exhibit Builder blocks for a rich presentation experience.
6 |
7 | ## System Requirements
8 |
9 | * Omeka Classic 2.3 and up
10 | * IIIF image server pointing to the Omeka installation's files/original directory (optional if you will only be importing content from existing manifests)
11 |
12 | ## Optional Requirements
13 |
14 | IIIF Toolkit can integrate with several popular Omeka rich presentation plugins. At the moment, the following are officially supported:
15 |
16 | * Exhibits Builder 3.x and up
17 | * Simple Pages 3.x and up
18 | * Neatline 2.2.x and up
19 |
20 | ## Installation
21 |
22 | * Clone this repository to the ```plugins``` directory of your Omeka installation.
23 | * Sign in as a super user.
24 | * In the top menu bar, select "Plugins".
25 | * Find IIIF Toolkit in the list of plugins and select "Install".
26 | * If you plan to serve your own images via IIIF, see "Pointing a IIIF image server" for details.
27 | * Select "Save Changes" to continue.
28 |
29 | ### Pointing a IIIF image server
30 |
31 | If you plan to serve your own images via IIIF, you must install a IIIF image server pointed to the Omeka installation's ```files/original``` directory. Please consult the documentation for your preferred IIIF image server for setup instructions.
32 |
33 | After setting up your IIIF image server, you can set the correspondence between file names in ```files/original``` and the image server's URIs.
34 |
35 | * Sign in as a super user.
36 | * In the top menu bar, select "Plugins".
37 | * Find IIIF Toolkit in the list of plugins and select "Configure".
38 | * Enter the server, prefix and identifier portion of a standard IIIF image request URI to your IIIF image server in the "IIIF Prefix" option. The following placeholders can be used to represent file-specific properties in the identifier portion:
39 | * ```{FULLNAME}```: The full name of the file (e.g. ```8997b027303b523ab7c4351c4761e4a0.jpg```)
40 | * ```{FILENAME}```: The name of the file without the extension (e.g. ```8997b027303b523ab7c4351c4761e4a0```)
41 | * ```{EXTENSION}```: The extension of the file, without the leading dot (e.g. ```jpg```)
42 |
43 | For example, if your IIIF image server would serve an image as ```http://iiif.example.org/images/8997b027303b523ab7c4351c4761e4a0/full/full/0/default.jpg```, you can enter ```http://iiif.example.org/images/{FILENAME}``` for IIIF Prefix.
44 |
45 |
46 | ## Upgrading
47 |
48 | Note: It is strongly recommended that you back up or snapshot the Omeka installation before upgrading, in case of unwanted changes or errors.
49 |
50 | * Run ```git pull``` or replace the directory with a download.
51 | * Sign in as a super user.
52 | * In the top menu bar, select "Plugins".
53 | * Find IIIF Toolkit in the list of plugins and select "Upgrade".
54 |
55 | ## License
56 |
57 | IIIF Toolkit is licensed under Apache License 2.0.
--------------------------------------------------------------------------------
/config_form.php:
--------------------------------------------------------------------------------
1 | removeDecorator('Form');
4 | $form->removeDecorator('Zend_Form_Decorator_Form');
5 | echo $form;
6 | ?>
--------------------------------------------------------------------------------
/controllers/AnnotationController.php:
--------------------------------------------------------------------------------
1 | getParam('id');
17 | $item = get_record_by_id('Item', $id);
18 | if (!$item) {
19 | throw new Omeka_Controller_Exception_404;
20 | }
21 | // Respond with JSON
22 | try {
23 | $jsonData = IiifItems_Util_Annotation::buildList($item);
24 | $this->__respondWithJson($jsonData);
25 | } catch (Exception $e) {
26 | $this->__respondWithJson(array(
27 | 'message' => $e->getMessage()
28 | ), 500);
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/controllers/ManifestController.php:
--------------------------------------------------------------------------------
1 | getParam('id');
13 | $type = $this->getParam('things');
14 | $class = Inflector::camelize(Inflector::singularize($type));
15 | $thing = get_record_by_id($class, $id);
16 | if (empty($thing) || !in_array($class, self::$allowedThings)) {
17 | throw new Omeka_Controller_Exception_404;
18 | }
19 |
20 | //Respond with JSON
21 | try {
22 | switch ($class) {
23 | case 'Collection':
24 | $jsonData = IiifItems_Util_Manifest::buildManifest($thing, is_admin_theme());
25 | IiifItems_Util_Search::insertSearchApiFor($thing, $jsonData);
26 | break;
27 | case 'Item':
28 | $jsonData = IiifItems_Util_Manifest::buildItemManifest($thing);
29 | if ($thing->item_type_id != get_option('iiifitems_annotation_item_type')) {
30 | IiifItems_Util_Search::insertSearchApiFor($thing, $jsonData);
31 | }
32 | break;
33 | case 'File': $jsonData = IiifItems_Util_Manifest::buildFileManifest($thing); break;
34 | case 'ExhibitPageBlock': $jsonData = IiifItems_Util_Manifest::buildExhibitPageBlockManifest($thing); break;
35 | }
36 | $this->__respondWithJson($jsonData);
37 | } catch (Exception $e) {
38 | $this->__respondWithJson(array(
39 | 'message' => $e->getMessage()
40 | ), 500);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/controllers/MiradorController.php:
--------------------------------------------------------------------------------
1 | getParam('things');
18 | $class = Inflector::camelize(Inflector::singularize($type));
19 | if (!in_array($class, self::$allowedThings)) {
20 | throw new Omeka_Controller_Exception_404;
21 | }
22 | $this->__passModelToView();
23 | }
24 |
25 | /**
26 | * Renders a Mirador viewer featuring multiple items and/or manifests.
27 | * Pass GET parameter items=(comma separated list of item IDs) to embed items.
28 | * Pass GET parameter u[]=(URL) to embed manifests
29 | *
30 | * GET iiif-items/multiviewer
31 | */
32 | public function multiviewerAction() {
33 | if ($this->getParam('items')) {
34 | $this->view->item_ids = explode(',', $this->getParam('items'));
35 | }
36 | $this->view->manifests = $this->getParam('u');
37 | $this->view->collections = $this->getParam('c');
38 | $this->view->popup = $this->getParam('p');
39 | }
40 |
41 | /**
42 | * Renders a minimal Mirador viewer for embedding in Neatline.
43 | *
44 | * GET iiif-items/nlmirador/:id
45 | */
46 | public function neatlineAction() {
47 | $this->view->itemId = $this->getParam('id');
48 | }
49 |
50 | /**
51 | * Renders an annotation-enabled Mirador viewer for the given manifest-type collection or non-annotation item.
52 | * GET: :things/:id/annotator
53 | *
54 | * @throws Omeka_Controller_Exception_404
55 | */
56 | public function annotatorAction() {
57 | // Check existence
58 | $id = $this->getParam('id');
59 | $type = $this->getParam('things');
60 | $class = Inflector::titleize(Inflector::singularize($type));
61 | $thing = get_record_by_id($class, $id);
62 | if (empty($thing) || !in_array($class, self::$allowedThings)) {
63 | throw new Omeka_Controller_Exception_404;
64 | }
65 | // Collection
66 | if ($class == 'Collection') {
67 | // Reject Collection-type items
68 | if (raw_iiif_metadata($thing, 'iiifitems_collection_type_element') == 'Collection') {
69 | throw new Omeka_Controller_Exception_404;
70 | }
71 | $this->__passModelToView();
72 | return;
73 | }
74 | // Item
75 | elseif ($class == 'Item') {
76 | // Reject Annotation-type items
77 | if ($thing->item_type_id == get_option('iiifitems_annotation_item_type')) {
78 | throw new Omeka_Controller_Exception_404;
79 | }
80 | $this->__passModelToView();
81 | return;
82 | }
83 | // Reject all others
84 | $this->__respondWithJson(null, 400);
85 | }
86 | }
87 | ?>
88 |
--------------------------------------------------------------------------------
/controllers/SearchController.php:
--------------------------------------------------------------------------------
1 | getParam('id');
13 | $type = $this->getParam('things');
14 | $class = Inflector::titleize(Inflector::singularize($type));
15 | $thing = get_record_by_id($class, $id);
16 | if (empty($thing) || !in_array($class, self::$allowedThings)) {
17 | throw new Omeka_Controller_Exception_404;
18 | }
19 |
20 | try {
21 | $results = IiifItems_Util_Search::findResultsFor($thing, $this->getParam('q'), public_full_url() . '?' . http_build_query($_GET));
22 | $this->__respondWithJson($results);
23 | } catch (Exception $ex) {
24 | $this->__respondWithJson(null, 400);
25 | }
26 | return;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/languages/en.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utlib/IiifItems/fb7f13a3fba6f96ab436c2bf464b6a12d3caa59c/languages/en.mo
--------------------------------------------------------------------------------
/languages/fr.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/utlib/IiifItems/fb7f13a3fba6f96ab436c2bf464b6a12d3caa59c/languages/fr.mo
--------------------------------------------------------------------------------
/languages/special_strings.php:
--------------------------------------------------------------------------------
1 | isActive()) {
46 | $this->initialize();
47 | $className = get_called_class();
48 | foreach ($this->_hooks as $hook) {
49 | add_plugin_hook($hook, array($this, 'hook' . Inflector::camelize($hook)));
50 | }
51 | foreach ($this->_filters as $filter) {
52 | add_filter($filter, array($this, 'filter' . Inflector::camelize($filter)));
53 | }
54 | }
55 | }
56 |
57 | /**
58 | * Echo an element-element text pair on admin-facing pages
59 | *
60 | * @param string $label The label for the element
61 | * @param string $id The HTML id attribute
62 | * @param string $entry The text for the element
63 | * @param boolean $html Whether the text is already HTML
64 | */
65 | protected function _adminElementTextPair($label, $id, $entry, $html) {
66 | echo '
' . ($html ? $entry : ('
'. html_escape($entry) .'
')) . '
';
67 | }
68 |
69 | /**
70 | * Echo an element-element text pair on public-facing pages
71 | *
72 | * @param string $label The label for the element
73 | * @param string $id The HTML id attribute
74 | * @param string $entry The text for the element
75 | * @param boolean $html Whether the text is already HTML
76 | */
77 | protected function _publicElementTextPair($label, $id, $entry, $html) {
78 | echo '