diva.js 6.0.2 → 7.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.clang-format +7 -0
- package/.github/workflows/npm-publish.yml +45 -0
- package/LICENSE +55 -0
- package/Makefile +75 -0
- package/README.md +15 -114
- package/elm.json +32 -0
- package/package.json +12 -59
- package/review/elm.json +52 -0
- package/review/src/ReviewConfig.elm +87 -0
- package/scripts/elm-esm.sh +40 -0
- package/scripts/minify-css.mjs +31 -0
- package/src/Filters.elm +1044 -0
- package/src/Main.elm +1217 -0
- package/src/Model.elm +213 -0
- package/src/Msg.elm +59 -0
- package/src/Utilities.elm +46 -0
- package/src/View/CollectionExplorer.elm +172 -0
- package/src/View/Helpers.elm +86 -0
- package/src/View/HtmlRenderer.elm +136 -0
- package/src/View/Icons.elm +159 -0
- package/src/View/ManifestInfoModal.elm +363 -0
- package/src/View/PageViewModal.elm +1046 -0
- package/src/View/Sidebar.elm +786 -0
- package/src/View/Toolbar.elm +189 -0
- package/src/View.elm +244 -0
- package/src/diva.ts +802 -0
- package/src/filters.ts +1843 -0
- package/src/styles/app.css +328 -0
- package/src/styles/collection.css +75 -0
- package/src/styles/modal.css +388 -0
- package/src/styles/sidebar.css +215 -0
- package/src/styles/theme.css +39 -0
- package/src/styles/toolbar.css +154 -0
- package/src/viewer-element.ts +1307 -0
- package/testing/index.html +52 -0
- package/testing/testing.html +231 -0
- package/tsconfig.json +12 -0
- package/AUTHORS +0 -22
- package/build/diva.css +0 -554
- package/build/diva.css.map +0 -1
- package/build/diva.js +0 -9
- package/build/diva.js.map +0 -1
- package/build/plugins/download.js +0 -2
- package/build/plugins/download.js.map +0 -1
- package/build/plugins/manipulation.js +0 -2
- package/build/plugins/manipulation.js.map +0 -1
- package/build/plugins/metadata.js +0 -2
- package/build/plugins/metadata.js.map +0 -1
- package/index.html +0 -28
- package/karma.conf.js +0 -87
- package/source/css/_mixins.scss +0 -43
- package/source/css/_variables.scss +0 -50
- package/source/css/_viewer.scss +0 -462
- package/source/css/diva.scss +0 -15
- package/source/css/plugins/_manipulation.scss +0 -228
- package/source/css/plugins/_metadata.scss +0 -31
- package/source/img/adjust.svg +0 -11
- package/source/img/book-view.svg +0 -6
- package/source/img/close.svg +0 -6
- package/source/img/download.svg +0 -6
- package/source/img/from-fullscreen.svg +0 -8
- package/source/img/grid-fewer.svg +0 -6
- package/source/img/grid-more.svg +0 -6
- package/source/img/grid-view.svg +0 -6
- package/source/img/link.svg +0 -6
- package/source/img/metadata.svg +0 -9
- package/source/img/page-view.svg +0 -6
- package/source/img/to-fullscreen.svg +0 -11
- package/source/img/zoom-in.svg +0 -6
- package/source/img/zoom-out.svg +0 -7
- package/source/js/composite-image.js +0 -174
- package/source/js/diva-global.js +0 -7
- package/source/js/diva.js +0 -1543
- package/source/js/document-handler.js +0 -180
- package/source/js/document-layout.js +0 -286
- package/source/js/exceptions.js +0 -26
- package/source/js/gesture-events.js +0 -190
- package/source/js/grid-handler.js +0 -122
- package/source/js/iiif-source-adapter.js +0 -63
- package/source/js/image-cache.js +0 -113
- package/source/js/image-manifest.js +0 -157
- package/source/js/image-request-handler.js +0 -76
- package/source/js/interpolate-animation.js +0 -122
- package/source/js/page-layouts/book-layout.js +0 -161
- package/source/js/page-layouts/grid-layout.js +0 -97
- package/source/js/page-layouts/index.js +0 -38
- package/source/js/page-layouts/page-dimensions.js +0 -9
- package/source/js/page-layouts/singles-layout.js +0 -27
- package/source/js/page-overlay-manager.js +0 -102
- package/source/js/page-tools-overlay.js +0 -95
- package/source/js/parse-iiif-manifest.js +0 -302
- package/source/js/plugins/_filters.js +0 -679
- package/source/js/plugins/download.js +0 -83
- package/source/js/plugins/manipulation.js +0 -837
- package/source/js/plugins/metadata.js +0 -190
- package/source/js/renderer.js +0 -584
- package/source/js/settings-view.js +0 -30
- package/source/js/tile-coverage-map.js +0 -25
- package/source/js/toolbar.js +0 -573
- package/source/js/utils/dragscroll.js +0 -106
- package/source/js/utils/elt.js +0 -94
- package/source/js/utils/events.js +0 -190
- package/source/js/utils/get-scrollbar-width.js +0 -29
- package/source/js/utils/hash-params.js +0 -86
- package/source/js/utils/parse-label-value.js +0 -34
- package/source/js/utils/vanilla.kinetic.js +0 -527
- package/source/js/validation-runner.js +0 -177
- package/source/js/viewer-core.js +0 -1514
- package/source/js/viewport.js +0 -143
- package/test/_setup.js +0 -13
- package/test/composite-image_test.js +0 -94
- package/test/diva_test.js +0 -43
- package/test/hash-params_test.js +0 -221
- package/test/image-cache_test.js +0 -106
- package/test/main.js +0 -6
- package/test/manifests/beromunsterManifest.json +0 -15514
- package/test/manifests/iiifv2.json +0 -11032
- package/test/manifests/iiifv2pages.json +0 -30437
- package/test/manifests/iiifv3.json +0 -10965
- package/test/navigation_test.js +0 -355
- package/test/parse-iiif-manifest_test.js +0 -68
- package/test/public_test.js +0 -881
- package/test/settings_test.js +0 -487
- package/test/utils/book-layout_test.js +0 -148
- package/test/utils/elt_test.js +0 -102
- package/test/utils/events_test.js +0 -245
- package/test/utils/hash-params_test.js +0 -79
- package/test/utils/parse-label-value_test.js +0 -45
- package/test/z_plugins_test.js +0 -180
- package/webpack.config.js +0 -58
- package/webpack.config.test.js +0 -45
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import parseLabelValue from './utils/parse-label-value';
|
|
2
|
-
|
|
3
|
-
const getMaxZoomLevel = (width, height) =>
|
|
4
|
-
{
|
|
5
|
-
const largestDimension = Math.max(width, height);
|
|
6
|
-
if (largestDimension < 128)
|
|
7
|
-
return 0;
|
|
8
|
-
return Math.ceil(Math.log((largestDimension + 1) / (256 + 1)) / Math.log(2));
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const incorporateZoom = (imageDimension, zoomDifference) => imageDimension / (Math.pow(2, zoomDifference));
|
|
12
|
-
|
|
13
|
-
const getOtherImageData = (otherImages, lowestMaxZoom) =>
|
|
14
|
-
{
|
|
15
|
-
return otherImages.map( (itm) =>
|
|
16
|
-
{
|
|
17
|
-
const w = itm.width;
|
|
18
|
-
const h = itm.height;
|
|
19
|
-
const info = parseImageInfo(itm);
|
|
20
|
-
const url = info.url.slice(-1) !== '/' ? info.url + '/' : info.url; // append trailing slash to url if it's not there.
|
|
21
|
-
|
|
22
|
-
const dims = new Array(lowestMaxZoom + 1);
|
|
23
|
-
for (let j = 0; j < lowestMaxZoom + 1; j++)
|
|
24
|
-
{
|
|
25
|
-
dims[j] = {
|
|
26
|
-
h: Math.floor(incorporateZoom(h, lowestMaxZoom - j)),
|
|
27
|
-
w: Math.floor(incorporateZoom(w, lowestMaxZoom - j))
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
f: info.url,
|
|
33
|
-
url: url,
|
|
34
|
-
il: itm.label || "",
|
|
35
|
-
d: dims
|
|
36
|
-
};
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const getIIIFPresentationVersion = (context) =>
|
|
41
|
-
{
|
|
42
|
-
if (context === "http://iiif.io/api/presentation/2/context.json")
|
|
43
|
-
return 2;
|
|
44
|
-
else if (Array.isArray(context) && context.includes("http://iiif.io/api/presentation/2/context.json"))
|
|
45
|
-
return 2;
|
|
46
|
-
else if (Array.isArray(context) && context.includes("http://iiif.io/api/presentation/3/context.json"))
|
|
47
|
-
return 3;
|
|
48
|
-
else
|
|
49
|
-
return 2; // Assume a v2 manifest.
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Parses an IIIF Presentation API Manifest and converts it into a Diva.js-format object
|
|
54
|
-
* (See https://github.com/DDMAL/diva.js/wiki/Development-notes#data-received-through-ajax-request)
|
|
55
|
-
*
|
|
56
|
-
* @param {Object} manifest - an object that represents a valid IIIF manifest
|
|
57
|
-
* @returns {Object} divaServiceBlock - the data needed by Diva to show a view of a single document
|
|
58
|
-
*/
|
|
59
|
-
export default function parseIIIFManifest (manifest)
|
|
60
|
-
{
|
|
61
|
-
let ctx = manifest["@context"];
|
|
62
|
-
|
|
63
|
-
if (!ctx)
|
|
64
|
-
{
|
|
65
|
-
console.error("Invalid IIIF Manifest; No @context found.");
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const version = getIIIFPresentationVersion(ctx);
|
|
70
|
-
const sequence = manifest.sequences ? manifest.sequences[0] : null;
|
|
71
|
-
const canvases = sequence ? sequence.canvases : manifest.items;
|
|
72
|
-
const numCanvases = canvases.length;
|
|
73
|
-
|
|
74
|
-
const pages = new Array(canvases.length);
|
|
75
|
-
|
|
76
|
-
let thisCanvas,
|
|
77
|
-
thisResource,
|
|
78
|
-
thisImage,
|
|
79
|
-
secondaryImages,
|
|
80
|
-
otherImages = [],
|
|
81
|
-
context,
|
|
82
|
-
url,
|
|
83
|
-
info,
|
|
84
|
-
imageAPIVersion,
|
|
85
|
-
width,
|
|
86
|
-
height,
|
|
87
|
-
maxZoom,
|
|
88
|
-
canvas,
|
|
89
|
-
label,
|
|
90
|
-
imageLabel,
|
|
91
|
-
zoomDimensions,
|
|
92
|
-
widthAtCurrentZoomLevel,
|
|
93
|
-
heightAtCurrentZoomLevel;
|
|
94
|
-
|
|
95
|
-
let lowestMaxZoom = 100;
|
|
96
|
-
let maxRatio = 0;
|
|
97
|
-
let minRatio = 100;
|
|
98
|
-
|
|
99
|
-
// quickly determine the lowest possible max zoom level (i.e., the upper bound for images) across all canvases.
|
|
100
|
-
// while we're here, compute the global ratios as well.
|
|
101
|
-
for (let z = 0; z < numCanvases; z++)
|
|
102
|
-
{
|
|
103
|
-
const c = canvases[z];
|
|
104
|
-
const w = c.width;
|
|
105
|
-
const h = c.height;
|
|
106
|
-
const mz = getMaxZoomLevel(w, h);
|
|
107
|
-
const ratio = h / w;
|
|
108
|
-
maxRatio = Math.max(ratio, maxRatio);
|
|
109
|
-
minRatio = Math.min(ratio, minRatio);
|
|
110
|
-
|
|
111
|
-
lowestMaxZoom = Math.min(lowestMaxZoom, mz);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/*
|
|
115
|
-
These arrays need to be pre-initialized since we will do arithmetic and value checking on them
|
|
116
|
-
*/
|
|
117
|
-
const totalWidths = new Array(lowestMaxZoom + 1).fill(0);
|
|
118
|
-
const totalHeights = new Array(lowestMaxZoom + 1).fill(0);
|
|
119
|
-
const maxWidths = new Array(lowestMaxZoom + 1).fill(0);
|
|
120
|
-
const maxHeights = new Array(lowestMaxZoom + 1).fill(0);
|
|
121
|
-
|
|
122
|
-
for (let i = 0; i < numCanvases; i++)
|
|
123
|
-
{
|
|
124
|
-
thisCanvas = canvases[i];
|
|
125
|
-
canvas = thisCanvas['@id'] || thisCanvas.id;
|
|
126
|
-
label = thisCanvas.label;
|
|
127
|
-
thisResource = thisCanvas.images ? thisCanvas.images[0].resource : thisCanvas.items[0].items[0].body;
|
|
128
|
-
|
|
129
|
-
/*
|
|
130
|
-
* If a canvas has multiple images it will be encoded
|
|
131
|
-
* with a resource type of "oa:Choice" (v2) or "Choice" (v3).
|
|
132
|
-
**/
|
|
133
|
-
otherImages = []; // reset array
|
|
134
|
-
if (thisResource['@type'] === "oa:Choice" || thisResource.type === "Choice")
|
|
135
|
-
{
|
|
136
|
-
thisImage = thisResource.default || thisResource.items[0];
|
|
137
|
-
secondaryImages = thisResource.item || thisResource.items.slice(1);
|
|
138
|
-
otherImages = getOtherImageData(secondaryImages, lowestMaxZoom);
|
|
139
|
-
}
|
|
140
|
-
else
|
|
141
|
-
{
|
|
142
|
-
thisImage = thisResource;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Prioritize the canvas height / width first, since images may not have h/w
|
|
146
|
-
width = thisCanvas.width || thisImage.width;
|
|
147
|
-
height = thisCanvas.height || thisImage.height;
|
|
148
|
-
|
|
149
|
-
if (width <= 0 || height <= 0)
|
|
150
|
-
{
|
|
151
|
-
console.warn('Invalid width or height for canvas ' + label + '. Skipping');
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
maxZoom = getMaxZoomLevel(width, height);
|
|
156
|
-
|
|
157
|
-
imageLabel = thisImage.label || null;
|
|
158
|
-
|
|
159
|
-
info = parseImageInfo(thisImage);
|
|
160
|
-
url = info.url.slice(-1) !== '/' ? info.url + '/' : info.url; // append trailing slash to url if it's not there.
|
|
161
|
-
|
|
162
|
-
context = thisImage.service['@context'] || thisImage.service.type;
|
|
163
|
-
|
|
164
|
-
if (context === 'http://iiif.io/api/image/2/context.json' || context === "ImageService2")
|
|
165
|
-
{
|
|
166
|
-
imageAPIVersion = 2;
|
|
167
|
-
}
|
|
168
|
-
else if (context === 'http://library.stanford.edu/iiif/image-api/1.1/context.json')
|
|
169
|
-
{
|
|
170
|
-
imageAPIVersion = 1.1;
|
|
171
|
-
}
|
|
172
|
-
else
|
|
173
|
-
{
|
|
174
|
-
imageAPIVersion = 1.0;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
zoomDimensions = new Array(lowestMaxZoom + 1);
|
|
178
|
-
|
|
179
|
-
for (let k = 0; k < lowestMaxZoom + 1; k++)
|
|
180
|
-
{
|
|
181
|
-
widthAtCurrentZoomLevel = Math.floor(incorporateZoom(width, lowestMaxZoom - k));
|
|
182
|
-
heightAtCurrentZoomLevel = Math.floor(incorporateZoom(height, lowestMaxZoom - k));
|
|
183
|
-
zoomDimensions[k] = {
|
|
184
|
-
h: heightAtCurrentZoomLevel,
|
|
185
|
-
w: widthAtCurrentZoomLevel
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
totalWidths[k] += widthAtCurrentZoomLevel;
|
|
189
|
-
totalHeights[k] += heightAtCurrentZoomLevel;
|
|
190
|
-
maxWidths[k] = Math.max(widthAtCurrentZoomLevel, maxWidths[k]);
|
|
191
|
-
maxHeights[k] = Math.max(heightAtCurrentZoomLevel, maxHeights[k]);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
let isPaged = thisCanvas.viewingHint !== 'non-paged' || (thisCanvas.behavior ? thisCanvas.behavior[0] !== 'non-paged' : false);
|
|
195
|
-
let isFacing = thisCanvas.viewingHint === 'facing-pages' || (thisCanvas.behavior ? thisCanvas.behavior[0] === 'facing-pages' : false);
|
|
196
|
-
|
|
197
|
-
pages[i] = {
|
|
198
|
-
d: zoomDimensions,
|
|
199
|
-
m: maxZoom,
|
|
200
|
-
l: label, // canvas label ('page 1, page 2', etc.)
|
|
201
|
-
il: imageLabel, // default image label ('primary image', 'UV light', etc.)
|
|
202
|
-
f: info.url,
|
|
203
|
-
url: url,
|
|
204
|
-
api: imageAPIVersion,
|
|
205
|
-
paged: isPaged,
|
|
206
|
-
facingPages: isFacing,
|
|
207
|
-
canvas: canvas,
|
|
208
|
-
otherImages: otherImages,
|
|
209
|
-
xoffset: info.x || null,
|
|
210
|
-
yoffset: info.y || null
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const averageWidths = new Array(lowestMaxZoom + 1);
|
|
215
|
-
const averageHeights = new Array(lowestMaxZoom + 1);
|
|
216
|
-
|
|
217
|
-
for (let a = 0; a < lowestMaxZoom + 1; a++)
|
|
218
|
-
{
|
|
219
|
-
averageWidths[a] = totalWidths[a] / numCanvases;
|
|
220
|
-
averageHeights[a] = totalHeights[a] / numCanvases;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const dims = {
|
|
224
|
-
a_wid: averageWidths,
|
|
225
|
-
a_hei: averageHeights,
|
|
226
|
-
max_w: maxWidths,
|
|
227
|
-
max_h: maxHeights,
|
|
228
|
-
max_ratio: maxRatio,
|
|
229
|
-
min_ratio: minRatio,
|
|
230
|
-
t_hei: totalHeights,
|
|
231
|
-
t_wid: totalWidths
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
// assumes paged is false for non-paged values
|
|
235
|
-
return {
|
|
236
|
-
version: version,
|
|
237
|
-
item_title: parseLabelValue(manifest).label,
|
|
238
|
-
metadata: manifest.metadata || null,
|
|
239
|
-
dims: dims,
|
|
240
|
-
max_zoom: lowestMaxZoom,
|
|
241
|
-
pgs: pages,
|
|
242
|
-
paged: manifest.viewingHint === 'paged' || (manifest.behaviour ? manifest.behaviour[0] === 'paged' : false) || (sequence ? sequence.viewingHint === 'paged' : false)
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Takes in a resource block from a canvas and outputs the following information associated with that resource:
|
|
248
|
-
* - Image URL
|
|
249
|
-
* - Image region to be displayed
|
|
250
|
-
*
|
|
251
|
-
* @param {Object} resource - an object representing the resource block of a canvas section in a IIIF manifest
|
|
252
|
-
* @returns {Object} imageInfo - an object containing image URL and region
|
|
253
|
-
*/
|
|
254
|
-
function parseImageInfo (resource)
|
|
255
|
-
{
|
|
256
|
-
let url = resource['@id'] || resource.id;
|
|
257
|
-
const fragmentRegex = /#xywh=([0-9]+,[0-9]+,[0-9]+,[0-9]+)/;
|
|
258
|
-
let xywh = '';
|
|
259
|
-
let stripURL = true;
|
|
260
|
-
|
|
261
|
-
if (/\/([0-9]+,[0-9]+,[0-9]+,[0-9]+)\//.test(url))
|
|
262
|
-
{
|
|
263
|
-
// if resource in image API format, extract region x,y,w,h from URL (after 4th slash from last)
|
|
264
|
-
// matches coordinates in URLs of the form http://www.example.org/iiif/book1-page1/40,50,1200,1800/full/0/default.jpg
|
|
265
|
-
const urlArray = url.split('/');
|
|
266
|
-
xywh = urlArray[urlArray.length - 4];
|
|
267
|
-
}
|
|
268
|
-
else if (fragmentRegex.test(url))
|
|
269
|
-
{
|
|
270
|
-
// matches coordinates of the style http://www.example.org/iiif/book1/canvas/p1#xywh=50,50,320,240
|
|
271
|
-
const result = fragmentRegex.exec(url);
|
|
272
|
-
xywh = result[1];
|
|
273
|
-
}
|
|
274
|
-
else if (resource.service && (resource.service['@id'] || resource.service.id))
|
|
275
|
-
{
|
|
276
|
-
// this URL excludes region parameters so we don't need to remove them
|
|
277
|
-
url = resource.service['@id'] || resource.service.id;
|
|
278
|
-
stripURL = false;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (stripURL)
|
|
282
|
-
{
|
|
283
|
-
// extract URL up to identifier (we eliminate the last 5 parameters: /region/size/rotation/quality.format)
|
|
284
|
-
url = url.split('/').slice(0, -4).join('/');
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const imageInfo = {
|
|
288
|
-
url: url
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
if (xywh.length)
|
|
292
|
-
{
|
|
293
|
-
// parse into separate components
|
|
294
|
-
const dimensions = xywh.split(',');
|
|
295
|
-
imageInfo.x = parseInt(dimensions[0], 10);
|
|
296
|
-
imageInfo.y = parseInt(dimensions[1], 10);
|
|
297
|
-
imageInfo.w = parseInt(dimensions[2], 10);
|
|
298
|
-
imageInfo.h = parseInt(dimensions[3], 10);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return imageInfo;
|
|
302
|
-
}
|