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
package/source/js/viewer-core.js
DELETED
|
@@ -1,1514 +0,0 @@
|
|
|
1
|
-
import { elt } from './utils/elt';
|
|
2
|
-
import getScrollbarWidth from './utils/get-scrollbar-width';
|
|
3
|
-
import gestureEvents from './gesture-events';
|
|
4
|
-
import diva from './diva-global';
|
|
5
|
-
import DocumentHandler from './document-handler';
|
|
6
|
-
import GridHandler from './grid-handler';
|
|
7
|
-
import PageOverlayManager from './page-overlay-manager';
|
|
8
|
-
import Renderer from './renderer';
|
|
9
|
-
import getPageLayouts from './page-layouts';
|
|
10
|
-
import createSettingsView from './settings-view';
|
|
11
|
-
import ValidationRunner from './validation-runner';
|
|
12
|
-
import Viewport from './viewport';
|
|
13
|
-
|
|
14
|
-
const debug = require('debug')('diva:ViewerCore');
|
|
15
|
-
|
|
16
|
-
function generateId() {
|
|
17
|
-
return generateId.counter++;
|
|
18
|
-
}
|
|
19
|
-
generateId.counter = 1;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// Define validations
|
|
23
|
-
const optionsValidations = [
|
|
24
|
-
{
|
|
25
|
-
key: 'goDirectlyTo',
|
|
26
|
-
validate: (value, settings) =>
|
|
27
|
-
{
|
|
28
|
-
if (value < 0 || value >= settings.manifest.pages.length)
|
|
29
|
-
return 0;
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
key: 'minPagesPerRow',
|
|
34
|
-
validate: (value) =>
|
|
35
|
-
{
|
|
36
|
-
return Math.max(2, value);
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
key: 'maxPagesPerRow',
|
|
41
|
-
validate: (value, settings) =>
|
|
42
|
-
{
|
|
43
|
-
return Math.max(value, settings.minPagesPerRow);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
key: 'pagesPerRow',
|
|
48
|
-
validate: (value, settings) =>
|
|
49
|
-
{
|
|
50
|
-
// Default to the maximum
|
|
51
|
-
if (value < settings.minPagesPerRow || value > settings.maxPagesPerRow)
|
|
52
|
-
return settings.maxPagesPerRow;
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
key: 'maxZoomLevel',
|
|
57
|
-
validate: (value, settings, config) =>
|
|
58
|
-
{
|
|
59
|
-
// Changing this value isn't really an error, it just depends on the
|
|
60
|
-
// source manifest
|
|
61
|
-
config.suppressWarning();
|
|
62
|
-
|
|
63
|
-
if (value < 0 || value > settings.manifest.maxZoom)
|
|
64
|
-
return settings.manifest.maxZoom;
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
key: 'minZoomLevel',
|
|
69
|
-
validate: (value, settings, config) =>
|
|
70
|
-
{
|
|
71
|
-
// Changes based on the manifest value shouldn't trigger a
|
|
72
|
-
// warning
|
|
73
|
-
if (value > settings.manifest.maxZoom)
|
|
74
|
-
{
|
|
75
|
-
config.suppressWarning();
|
|
76
|
-
return 0;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (value < 0 || value > settings.maxZoomLevel)
|
|
80
|
-
return 0;
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
key: 'zoomLevel',
|
|
85
|
-
validate: (value, settings, config) =>
|
|
86
|
-
{
|
|
87
|
-
if (value > settings.manifest.maxZoom)
|
|
88
|
-
{
|
|
89
|
-
config.suppressWarning();
|
|
90
|
-
return 0;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (value < settings.minZoomLevel || value > settings.maxZoomLevel)
|
|
94
|
-
return settings.minZoomLevel;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
];
|
|
98
|
-
|
|
99
|
-
export default class ViewerCore
|
|
100
|
-
{
|
|
101
|
-
constructor (element, options, publicInstance)
|
|
102
|
-
{
|
|
103
|
-
this.parentObject = element;
|
|
104
|
-
this.publicInstance = publicInstance;
|
|
105
|
-
|
|
106
|
-
// Things that cannot be changed because of the way they are used by the script
|
|
107
|
-
// Many of these are declared with arbitrary values that are changed later on
|
|
108
|
-
this.viewerState = {
|
|
109
|
-
currentPageIndices: [0], // The visible pages in the viewport
|
|
110
|
-
activePageIndex: 0, // The current 'active' page in the viewport
|
|
111
|
-
horizontalOffset: 0, // Distance from the center of the diva element to the top of the current page
|
|
112
|
-
horizontalPadding: 0, // Either the fixed padding or adaptive padding
|
|
113
|
-
ID: null, // The prefix of the IDs of the elements (usually 1-diva-)
|
|
114
|
-
initialKeyScroll: false, // Holds the initial state of enableKeyScroll
|
|
115
|
-
initialSpaceScroll: false, // Holds the initial state of enableSpaceScroll
|
|
116
|
-
innerElement: null, // The native .diva-outer DOM object
|
|
117
|
-
innerObject: {}, // document.getElementById(settings.ID + 'inner'), for selecting the .diva-inner element
|
|
118
|
-
isActiveDiva: true, // In the case that multiple diva panes exist on the same page, this should have events funneled to it.
|
|
119
|
-
isScrollable: true, // Used in enable/disableScrollable public methods
|
|
120
|
-
isZooming: false, // Flag to keep track of whether zooming is still in progress, for handleZoom
|
|
121
|
-
loaded: false, // A flag for when everything is loaded and ready to go.
|
|
122
|
-
manifest: null,
|
|
123
|
-
mobileWebkit: false, // Checks if the user is on a touch device (iPad/iPod/iPhone/Android)
|
|
124
|
-
numPages: 0, // Number of pages in the array
|
|
125
|
-
oldZoomLevel: -1, // Holds the previous zoom level after zooming in or out
|
|
126
|
-
options: options,
|
|
127
|
-
outerElement: null, // The native .diva-outer DOM object
|
|
128
|
-
outerObject: {}, // document.getElementById(settings.ID + 'outer'), for selecting the .diva-outer element
|
|
129
|
-
pageOverlays: new PageOverlayManager(),
|
|
130
|
-
pageTools: [], // The plugins which are enabled as page tools
|
|
131
|
-
parentObject: this.parentObject, // JQuery object referencing the parent element
|
|
132
|
-
pendingManifestRequest: null, // Reference to the xhr request retrieving the manifest. Used to cancel the request on destroy()
|
|
133
|
-
pluginInstances: [], // Filled with the enabled plugins from the registry
|
|
134
|
-
renderer: null,
|
|
135
|
-
resizeTimer: -1, // Holds the ID of the timeout used when resizing the window (for clearing)
|
|
136
|
-
scrollbarWidth: 0, // Set to the actual scrollbar width in init()
|
|
137
|
-
selector: '', // Uses the generated ID prefix to easily select elements
|
|
138
|
-
throbberTimeoutID: -1, // Holds the ID of the throbber loading timeout
|
|
139
|
-
toolbar: null, // Holds an object with some toolbar-related functions
|
|
140
|
-
verticalOffset: 0, // Distance from the center of the diva element to the left side of the current page
|
|
141
|
-
verticalPadding: 0, // Either the fixed padding or adaptive padding
|
|
142
|
-
viewHandler: null,
|
|
143
|
-
viewport: null, // Object caching the viewport dimensions
|
|
144
|
-
viewportElement: null,
|
|
145
|
-
viewportObject: null,
|
|
146
|
-
zoomDuration: 400
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
this.settings = createSettingsView([options, this.viewerState]);
|
|
150
|
-
|
|
151
|
-
// Generate an ID that can be used as a prefix for all the other IDs
|
|
152
|
-
const idNumber = generateId();
|
|
153
|
-
this.viewerState.ID = 'diva-' + idNumber + '-';
|
|
154
|
-
this.viewerState.selector = this.settings.ID;
|
|
155
|
-
|
|
156
|
-
// Aliases for compatibility
|
|
157
|
-
Object.defineProperties(this.settings, {
|
|
158
|
-
// Height of the document viewer pane
|
|
159
|
-
panelHeight: {
|
|
160
|
-
get: () =>
|
|
161
|
-
{
|
|
162
|
-
return this.viewerState.viewport.height;
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
// Width of the document viewer pane
|
|
166
|
-
panelWidth: {
|
|
167
|
-
get: () =>
|
|
168
|
-
{
|
|
169
|
-
return this.viewerState.viewport.width;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
this.optionsValidator = new ValidationRunner({
|
|
175
|
-
additionalProperties: [
|
|
176
|
-
{
|
|
177
|
-
key: 'manifest',
|
|
178
|
-
get: () =>
|
|
179
|
-
{
|
|
180
|
-
return this.viewerState.manifest;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
],
|
|
184
|
-
|
|
185
|
-
validations: optionsValidations
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
this.viewerState.scrollbarWidth = getScrollbarWidth();
|
|
189
|
-
|
|
190
|
-
// If window.orientation is defined, then it's probably mobileWebkit
|
|
191
|
-
this.viewerState.mobileWebkit = window.orientation !== undefined;
|
|
192
|
-
|
|
193
|
-
if (options.hashParamSuffix === null)
|
|
194
|
-
{
|
|
195
|
-
// Omit the suffix from the first instance
|
|
196
|
-
if (idNumber === 1)
|
|
197
|
-
options.hashParamSuffix = '';
|
|
198
|
-
else
|
|
199
|
-
options.hashParamSuffix = idNumber + '';
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Create the inner and outer panels
|
|
203
|
-
const innerElem = elt('div', this.elemAttrs('inner', { class: 'diva-inner' }));
|
|
204
|
-
const viewportElem = elt('div', this.elemAttrs('viewport'), innerElem);
|
|
205
|
-
const outerElem = elt('div', this.elemAttrs('outer'),
|
|
206
|
-
viewportElem,
|
|
207
|
-
elt('div', this.elemAttrs('throbber'),
|
|
208
|
-
[
|
|
209
|
-
elt('div', { class: 'cube cube1' }),
|
|
210
|
-
elt('div', { class: 'cube cube2' }),
|
|
211
|
-
elt('div', { class: 'cube cube3' }),
|
|
212
|
-
elt('div', { class: 'cube cube4' }),
|
|
213
|
-
elt('div', { class: 'cube cube5' }),
|
|
214
|
-
elt('div', { class: 'cube cube6' }),
|
|
215
|
-
elt('div', { class: 'cube cube7' }),
|
|
216
|
-
elt('div', { class: 'cube cube8' }),
|
|
217
|
-
elt('div', { class: 'cube cube9' }),
|
|
218
|
-
]
|
|
219
|
-
));
|
|
220
|
-
|
|
221
|
-
this.viewerState.innerElement = innerElem;
|
|
222
|
-
this.viewerState.viewportElement = viewportElem;
|
|
223
|
-
this.viewerState.outerElement = outerElem;
|
|
224
|
-
|
|
225
|
-
this.viewerState.innerObject = innerElem;
|
|
226
|
-
this.viewerState.viewportObject = viewportElem;
|
|
227
|
-
this.viewerState.outerObject = outerElem;
|
|
228
|
-
|
|
229
|
-
this.settings.parentObject.append(outerElem);
|
|
230
|
-
|
|
231
|
-
this.viewerState.viewport = new Viewport(this.viewerState.viewportElement, {
|
|
232
|
-
intersectionTolerance: this.settings.viewportMargin
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
this.boundScrollFunction = this.scrollFunction.bind(this);
|
|
236
|
-
this.boundEscapeListener = this.escapeListener.bind(this);
|
|
237
|
-
|
|
238
|
-
// Do all the plugin initialisation
|
|
239
|
-
this.initPlugins();
|
|
240
|
-
this.handleEvents();
|
|
241
|
-
|
|
242
|
-
// Show the throbber while waiting for the manifest to load
|
|
243
|
-
this.showThrobber();
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
isValidOption (key, value)
|
|
247
|
-
{
|
|
248
|
-
return this.optionsValidator.isValid(key, value, this.viewerState.options);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
elemAttrs (ident, base)
|
|
252
|
-
{
|
|
253
|
-
const attrs = {
|
|
254
|
-
id: this.settings.ID + ident,
|
|
255
|
-
class: 'diva-' + ident
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
if (base)
|
|
259
|
-
return Object.assign(attrs, base);
|
|
260
|
-
else
|
|
261
|
-
return attrs;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
getPageData (pageIndex, attribute)
|
|
265
|
-
{
|
|
266
|
-
return this.settings.manifest.pages[pageIndex].d[this.settings.zoomLevel][attribute];
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Reset some settings and empty the viewport
|
|
270
|
-
clearViewer ()
|
|
271
|
-
{
|
|
272
|
-
this.viewerState.viewport.top = 0;
|
|
273
|
-
|
|
274
|
-
// Clear all the timeouts to prevent undesired pages from loading
|
|
275
|
-
clearTimeout(this.viewerState.resizeTimer);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
hasChangedOption (options, key)
|
|
279
|
-
{
|
|
280
|
-
return key in options && options[key] !== this.settings[key];
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
//Shortcut for closing fullscreen with the escape key
|
|
284
|
-
escapeListener (e)
|
|
285
|
-
{
|
|
286
|
-
if (e.keyCode === 27)
|
|
287
|
-
{
|
|
288
|
-
this.publicInstance.leaveFullscreenMode();
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Update settings to match the specified options. Load the viewer,
|
|
294
|
-
* fire appropriate events for changed options.
|
|
295
|
-
*/
|
|
296
|
-
reloadViewer (newOptions)
|
|
297
|
-
{
|
|
298
|
-
const queuedEvents = [];
|
|
299
|
-
|
|
300
|
-
newOptions = this.optionsValidator.getValidatedOptions(this.settings, newOptions);
|
|
301
|
-
|
|
302
|
-
// Set the zoom level if valid and fire a ZoomLevelDidChange event
|
|
303
|
-
if (this.hasChangedOption(newOptions, 'zoomLevel'))
|
|
304
|
-
{
|
|
305
|
-
this.viewerState.oldZoomLevel = this.settings.zoomLevel;
|
|
306
|
-
this.viewerState.options.zoomLevel = newOptions.zoomLevel;
|
|
307
|
-
queuedEvents.push(["ZoomLevelDidChange", newOptions.zoomLevel]);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Set the pages per row if valid and fire an event
|
|
311
|
-
if (this.hasChangedOption(newOptions, 'pagesPerRow'))
|
|
312
|
-
{
|
|
313
|
-
this.viewerState.options.pagesPerRow = newOptions.pagesPerRow;
|
|
314
|
-
queuedEvents.push(["GridRowNumberDidChange", newOptions.pagesPerRow]);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Update verticallyOriented (no event fired)
|
|
318
|
-
if (this.hasChangedOption(newOptions, 'verticallyOriented'))
|
|
319
|
-
this.viewerState.options.verticallyOriented = newOptions.verticallyOriented;
|
|
320
|
-
|
|
321
|
-
// Show/Hide non-paged pages
|
|
322
|
-
if (this.hasChangedOption(newOptions, 'showNonPagedPages'))
|
|
323
|
-
{
|
|
324
|
-
this.viewerState.options.showNonPagedPages = newOptions.showNonPagedPages;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Update page position (no event fired here)
|
|
328
|
-
if ('goDirectlyTo' in newOptions)
|
|
329
|
-
{
|
|
330
|
-
this.viewerState.options.goDirectlyTo = newOptions.goDirectlyTo;
|
|
331
|
-
|
|
332
|
-
if ('verticalOffset' in newOptions)
|
|
333
|
-
this.viewerState.verticalOffset = newOptions.verticalOffset;
|
|
334
|
-
|
|
335
|
-
if ('horizontalOffset' in newOptions)
|
|
336
|
-
this.viewerState.horizontalOffset = newOptions.horizontalOffset;
|
|
337
|
-
}
|
|
338
|
-
else
|
|
339
|
-
{
|
|
340
|
-
// Otherwise the default is to remain on the current page
|
|
341
|
-
this.viewerState.options.goDirectlyTo = this.settings.activePageIndex;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (this.hasChangedOption(newOptions, 'inGrid') || this.hasChangedOption(newOptions, 'inBookLayout'))
|
|
345
|
-
{
|
|
346
|
-
if ('inGrid' in newOptions)
|
|
347
|
-
this.viewerState.options.inGrid = newOptions.inGrid;
|
|
348
|
-
|
|
349
|
-
if ('inBookLayout' in newOptions)
|
|
350
|
-
this.viewerState.options.inBookLayout = newOptions.inBookLayout;
|
|
351
|
-
|
|
352
|
-
queuedEvents.push(["ViewDidSwitch", this.settings.inGrid]);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Note: prepareModeChange() depends on inGrid and the vertical/horizontalOffset (for now)
|
|
356
|
-
if (this.hasChangedOption(newOptions, 'inFullscreen'))
|
|
357
|
-
{
|
|
358
|
-
this.viewerState.options.inFullscreen = newOptions.inFullscreen;
|
|
359
|
-
this.prepareModeChange(newOptions);
|
|
360
|
-
queuedEvents.push(["ModeDidSwitch", this.settings.inFullscreen]);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
this.clearViewer();
|
|
364
|
-
this.updateViewHandlerAndRendering();
|
|
365
|
-
|
|
366
|
-
if (this.viewerState.renderer)
|
|
367
|
-
{
|
|
368
|
-
// TODO: The usage of padding variables is still really
|
|
369
|
-
// messy and inconsistent
|
|
370
|
-
const rendererConfig = {
|
|
371
|
-
pageLayouts: getPageLayouts(this.settings),
|
|
372
|
-
padding: this.getPadding(),
|
|
373
|
-
maxZoomLevel: this.settings.inGrid ? null : this.viewerState.manifest.maxZoom,
|
|
374
|
-
verticallyOriented: this.settings.verticallyOriented || this.settings.inGrid,
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
const viewportPosition = {
|
|
378
|
-
zoomLevel: this.settings.inGrid ? null : this.settings.zoomLevel,
|
|
379
|
-
anchorPage: this.settings.goDirectlyTo,
|
|
380
|
-
verticalOffset: this.viewerState.verticalOffset,
|
|
381
|
-
horizontalOffset: this.viewerState.horizontalOffset
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
const sourceProvider = this.getCurrentSourceProvider();
|
|
385
|
-
|
|
386
|
-
if (debug.enabled)
|
|
387
|
-
{
|
|
388
|
-
const serialized = Object.keys(rendererConfig)
|
|
389
|
-
.filter(function (key)
|
|
390
|
-
{
|
|
391
|
-
// Too long
|
|
392
|
-
return key !== 'pageLayouts' && key !== 'padding';
|
|
393
|
-
})
|
|
394
|
-
.map(function (key)
|
|
395
|
-
{
|
|
396
|
-
const value = rendererConfig[key];
|
|
397
|
-
return key + ': ' + JSON.stringify(value);
|
|
398
|
-
})
|
|
399
|
-
.join(', ');
|
|
400
|
-
|
|
401
|
-
debug('reload with %s', serialized);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
this.viewerState.renderer.load(rendererConfig, viewportPosition, sourceProvider);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
queuedEvents.forEach( (params) =>
|
|
408
|
-
{
|
|
409
|
-
this.publish.apply(this, params);
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
return true;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Handles switching in and out of fullscreen mode
|
|
416
|
-
prepareModeChange (options)
|
|
417
|
-
{
|
|
418
|
-
// Toggle the classes
|
|
419
|
-
const changeClass = options.inFullscreen ? 'add' : 'remove';
|
|
420
|
-
this.viewerState.outerObject.classList[changeClass]('diva-fullscreen');
|
|
421
|
-
document.body.classList[changeClass]('diva-hide-scrollbar');
|
|
422
|
-
this.settings.parentObject.classList[changeClass]('diva-full-width');
|
|
423
|
-
|
|
424
|
-
// Adjust Diva's internal panel size, keeping the old values
|
|
425
|
-
const storedHeight = this.settings.panelHeight;
|
|
426
|
-
const storedWidth = this.settings.panelWidth;
|
|
427
|
-
this.viewerState.viewport.invalidate();
|
|
428
|
-
|
|
429
|
-
// If this isn't the original load, the offsets matter, and the position isn't being changed...
|
|
430
|
-
if (!this.viewerState.loaded && !this.settings.inGrid && !('verticalOffset' in options))
|
|
431
|
-
{
|
|
432
|
-
//get the updated panel size
|
|
433
|
-
const newHeight = this.settings.panelHeight;
|
|
434
|
-
const newWidth = this.settings.panelWidth;
|
|
435
|
-
|
|
436
|
-
//and re-center the new panel on the same point
|
|
437
|
-
this.viewerState.verticalOffset += ((storedHeight - newHeight) / 2);
|
|
438
|
-
this.viewerState.horizontalOffset += ((storedWidth - newWidth) / 2);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
//turn on/off escape key listener
|
|
442
|
-
if (options.inFullscreen)
|
|
443
|
-
document.addEventListener('keyup', this.boundEscapeListener);
|
|
444
|
-
else
|
|
445
|
-
document.removeEventListener('keyup', this.boundEscapeListener);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Update the view handler and the view rendering for the current view
|
|
449
|
-
updateViewHandlerAndRendering ()
|
|
450
|
-
{
|
|
451
|
-
const Handler = this.settings.inGrid ? GridHandler : DocumentHandler;
|
|
452
|
-
|
|
453
|
-
if (this.viewerState.viewHandler && !(this.viewerState.viewHandler instanceof Handler))
|
|
454
|
-
{
|
|
455
|
-
this.viewerState.viewHandler.destroy();
|
|
456
|
-
this.viewerState.viewHandler = null;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (!this.viewerState.viewHandler)
|
|
460
|
-
this.viewerState.viewHandler = new Handler(this);
|
|
461
|
-
|
|
462
|
-
if (!this.viewerState.renderer)
|
|
463
|
-
this.initializeRenderer();
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// TODO: This could probably be done upon ViewerCore initialization
|
|
467
|
-
initializeRenderer ()
|
|
468
|
-
{
|
|
469
|
-
const compatErrors = Renderer.getCompatibilityErrors();
|
|
470
|
-
|
|
471
|
-
if (compatErrors)
|
|
472
|
-
{
|
|
473
|
-
this.showError(compatErrors);
|
|
474
|
-
}
|
|
475
|
-
else
|
|
476
|
-
{
|
|
477
|
-
const options = {
|
|
478
|
-
viewport: this.viewerState.viewport,
|
|
479
|
-
outerElement: this.viewerState.outerElement,
|
|
480
|
-
innerElement: this.viewerState.innerElement,
|
|
481
|
-
settings: this.settings
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
const hooks = {
|
|
485
|
-
onViewWillLoad: () =>
|
|
486
|
-
{
|
|
487
|
-
this.viewerState.viewHandler.onViewWillLoad();
|
|
488
|
-
},
|
|
489
|
-
onViewDidLoad: () =>
|
|
490
|
-
{
|
|
491
|
-
this.updatePageOverlays();
|
|
492
|
-
this.viewerState.viewHandler.onViewDidLoad();
|
|
493
|
-
},
|
|
494
|
-
onViewDidUpdate: (pages, targetPage) =>
|
|
495
|
-
{
|
|
496
|
-
this.updatePageOverlays();
|
|
497
|
-
this.viewerState.viewHandler.onViewDidUpdate(pages, targetPage);
|
|
498
|
-
},
|
|
499
|
-
onViewDidTransition: () =>
|
|
500
|
-
{
|
|
501
|
-
this.updatePageOverlays();
|
|
502
|
-
},
|
|
503
|
-
onPageWillLoad: (pageIndex) =>
|
|
504
|
-
{
|
|
505
|
-
this.publish('PageWillLoad', pageIndex);
|
|
506
|
-
},
|
|
507
|
-
onZoomLevelWillChange: (zoomLevel) =>
|
|
508
|
-
{
|
|
509
|
-
this.publish('ZoomLevelWillChange', zoomLevel);
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
this.viewerState.renderer = new Renderer(options, hooks);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
getCurrentSourceProvider ()
|
|
518
|
-
{
|
|
519
|
-
if (this.settings.inGrid)
|
|
520
|
-
{
|
|
521
|
-
const gridSourceProvider = {
|
|
522
|
-
getAllZoomLevelsForPage: (page) =>
|
|
523
|
-
{
|
|
524
|
-
return [gridSourceProvider.getBestZoomLevelForPage(page)];
|
|
525
|
-
},
|
|
526
|
-
getBestZoomLevelForPage: (page) =>
|
|
527
|
-
{
|
|
528
|
-
const url = this.settings.manifest.getPageImageURL(page.index, {
|
|
529
|
-
width: page.dimensions.width
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
return {
|
|
533
|
-
zoomLevel: 1, // FIXME
|
|
534
|
-
rows: 1,
|
|
535
|
-
cols: 1,
|
|
536
|
-
tiles: [{
|
|
537
|
-
url: url,
|
|
538
|
-
zoomLevel: 1, // FIXME
|
|
539
|
-
row: 0,
|
|
540
|
-
col: 0,
|
|
541
|
-
dimensions: page.dimensions,
|
|
542
|
-
offset: {
|
|
543
|
-
top: 0,
|
|
544
|
-
left: 0
|
|
545
|
-
}
|
|
546
|
-
}]
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
return gridSourceProvider;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
const tileDimensions = {
|
|
555
|
-
width: this.settings.tileWidth,
|
|
556
|
-
height: this.settings.tileHeight
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
return {
|
|
560
|
-
getBestZoomLevelForPage: (page) =>
|
|
561
|
-
{
|
|
562
|
-
return this.settings.manifest.getPageImageTiles(page.index, Math.ceil(this.settings.zoomLevel), tileDimensions);
|
|
563
|
-
},
|
|
564
|
-
getAllZoomLevelsForPage: (page) =>
|
|
565
|
-
{
|
|
566
|
-
const levels = [];
|
|
567
|
-
const levelCount = this.viewerState.manifest.maxZoom;
|
|
568
|
-
|
|
569
|
-
for (let level=0; level <= levelCount; level++)
|
|
570
|
-
{
|
|
571
|
-
levels.push(this.settings.manifest.getPageImageTiles(page.index, level, tileDimensions));
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
levels.reverse();
|
|
575
|
-
|
|
576
|
-
return levels;
|
|
577
|
-
}
|
|
578
|
-
};
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
getPadding ()
|
|
582
|
-
{
|
|
583
|
-
let topPadding, leftPadding;
|
|
584
|
-
let docVPadding, docHPadding;
|
|
585
|
-
|
|
586
|
-
if (this.settings.inGrid)
|
|
587
|
-
{
|
|
588
|
-
docVPadding = this.settings.fixedPadding;
|
|
589
|
-
topPadding = leftPadding = docHPadding = 0;
|
|
590
|
-
}
|
|
591
|
-
else
|
|
592
|
-
{
|
|
593
|
-
topPadding = this.settings.verticallyOriented ? this.viewerState.verticalPadding : 0;
|
|
594
|
-
leftPadding = this.settings.verticallyOriented ? 0 : this.viewerState.horizontalPadding;
|
|
595
|
-
|
|
596
|
-
docVPadding = this.settings.verticallyOriented ? 0 : this.viewerState.verticalPadding;
|
|
597
|
-
docHPadding = this.settings.verticallyOriented ? this.viewerState.horizontalPadding : 0;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
return {
|
|
601
|
-
document: {
|
|
602
|
-
top: docVPadding,
|
|
603
|
-
bottom: docVPadding,
|
|
604
|
-
left: docHPadding,
|
|
605
|
-
right: docHPadding
|
|
606
|
-
},
|
|
607
|
-
page: {
|
|
608
|
-
top: topPadding,
|
|
609
|
-
bottom: 0,
|
|
610
|
-
left: leftPadding,
|
|
611
|
-
right: 0
|
|
612
|
-
}
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
updatePageOverlays ()
|
|
617
|
-
{
|
|
618
|
-
this.viewerState.pageOverlays.updateOverlays(
|
|
619
|
-
this.viewerState.renderer.getRenderedPages()
|
|
620
|
-
);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// Called to handle any zoom level
|
|
624
|
-
handleZoom (newZoomLevel, focalPoint)
|
|
625
|
-
{
|
|
626
|
-
// If the zoom level provided is invalid, return false
|
|
627
|
-
if (!this.isValidOption('zoomLevel', newZoomLevel))
|
|
628
|
-
return false;
|
|
629
|
-
|
|
630
|
-
// While zooming, don't update scroll offsets based on the scaled version of diva-inner
|
|
631
|
-
this.viewerState.viewportObject.removeEventListener('scroll', this.boundScrollFunction);
|
|
632
|
-
|
|
633
|
-
// If no focal point was given, zoom on the center of the viewport
|
|
634
|
-
if (!focalPoint)
|
|
635
|
-
{
|
|
636
|
-
const viewport = this.viewerState.viewport;
|
|
637
|
-
const currentRegion = this.viewerState.renderer.layout.getPageRegion(this.settings.activePageIndex);
|
|
638
|
-
|
|
639
|
-
focalPoint = {
|
|
640
|
-
anchorPage: this.settings.activePageIndex,
|
|
641
|
-
offset: {
|
|
642
|
-
left: (viewport.width / 2) - (currentRegion.left - viewport.left),
|
|
643
|
-
top: (viewport.height / 2) - (currentRegion.top - viewport.top)
|
|
644
|
-
}
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
const pageRegion = this.viewerState.renderer.layout.getPageRegion(focalPoint.anchorPage);
|
|
649
|
-
|
|
650
|
-
// calculate distance from cursor coordinates to center of viewport
|
|
651
|
-
const focalXToCenter = (pageRegion.left + focalPoint.offset.left) -
|
|
652
|
-
(this.settings.viewport.left + (this.settings.viewport.width / 2));
|
|
653
|
-
const focalYToCenter = (pageRegion.top + focalPoint.offset.top) -
|
|
654
|
-
(this.settings.viewport.top + (this.settings.viewport.height / 2));
|
|
655
|
-
|
|
656
|
-
const getPositionForZoomLevel = (zoomLevel, initZoom) =>
|
|
657
|
-
{
|
|
658
|
-
const zoomRatio = Math.pow(2, zoomLevel - initZoom);
|
|
659
|
-
|
|
660
|
-
//TODO(jeromepl): Calculate position from page top left to viewport top left
|
|
661
|
-
// calculate horizontal/verticalOffset: distance from viewport center to page upper left corner
|
|
662
|
-
const horizontalOffset = (focalPoint.offset.left * zoomRatio) - focalXToCenter;
|
|
663
|
-
const verticalOffset = (focalPoint.offset.top * zoomRatio) - focalYToCenter;
|
|
664
|
-
|
|
665
|
-
return {
|
|
666
|
-
zoomLevel: zoomLevel,
|
|
667
|
-
anchorPage: focalPoint.anchorPage,
|
|
668
|
-
verticalOffset: verticalOffset,
|
|
669
|
-
horizontalOffset: horizontalOffset
|
|
670
|
-
};
|
|
671
|
-
};
|
|
672
|
-
|
|
673
|
-
this.viewerState.options.zoomLevel = newZoomLevel;
|
|
674
|
-
let initialZoomLevel = this.viewerState.oldZoomLevel;
|
|
675
|
-
this.viewerState.oldZoomLevel = this.settings.zoomLevel;
|
|
676
|
-
const endPosition = getPositionForZoomLevel(newZoomLevel, initialZoomLevel);
|
|
677
|
-
this.viewerState.options.goDirectlyTo = endPosition.anchorPage;
|
|
678
|
-
this.viewerState.verticalOffset = endPosition.verticalOffset;
|
|
679
|
-
this.viewerState.horizontalOffset = endPosition.horizontalOffset;
|
|
680
|
-
|
|
681
|
-
this.viewerState.renderer.transitionViewportPosition({
|
|
682
|
-
duration: this.settings.zoomDuration,
|
|
683
|
-
parameters: {
|
|
684
|
-
zoomLevel: {
|
|
685
|
-
from: initialZoomLevel,
|
|
686
|
-
to: newZoomLevel
|
|
687
|
-
}
|
|
688
|
-
},
|
|
689
|
-
getPosition: (parameters) =>
|
|
690
|
-
{
|
|
691
|
-
return getPositionForZoomLevel(parameters.zoomLevel, initialZoomLevel);
|
|
692
|
-
},
|
|
693
|
-
onEnd: (info) =>
|
|
694
|
-
{
|
|
695
|
-
this.viewerState.viewportObject.addEventListener('scroll', this.boundScrollFunction);
|
|
696
|
-
|
|
697
|
-
if (info.interrupted)
|
|
698
|
-
this.viewerState.oldZoomLevel = newZoomLevel;
|
|
699
|
-
}
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
// Deactivate zoom buttons while zooming
|
|
703
|
-
let zoomInButton = document.getElementById(this.settings.selector + 'zoom-in-button');
|
|
704
|
-
let zoomOutButton = document.getElementById(this.settings.selector + 'zoom-out-button');
|
|
705
|
-
zoomInButton.disabled = true;
|
|
706
|
-
zoomOutButton.disabled = true;
|
|
707
|
-
setTimeout(() =>
|
|
708
|
-
{
|
|
709
|
-
zoomInButton.disabled = false;
|
|
710
|
-
zoomOutButton.disabled = false;
|
|
711
|
-
}, this.settings.zoomDuration);
|
|
712
|
-
|
|
713
|
-
// Send off the zoom level did change event.
|
|
714
|
-
this.publish("ZoomLevelDidChange", newZoomLevel);
|
|
715
|
-
|
|
716
|
-
return true;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
/*
|
|
720
|
-
Gets the Y-offset for a specific point on a specific page
|
|
721
|
-
Acceptable values for "anchor":
|
|
722
|
-
"top" (default) - will anchor top of the page to the top of the diva-outer element
|
|
723
|
-
"bottom" - top, s/top/bottom
|
|
724
|
-
"center" - will center the page on the diva element
|
|
725
|
-
Returned value will be the distance from the center of the diva-outer element to the top of the current page for the specified anchor
|
|
726
|
-
*/
|
|
727
|
-
getYOffset (pageIndex, anchor)
|
|
728
|
-
{
|
|
729
|
-
let pidx = (typeof(pageIndex) === "undefined" ? this.settings.activePageIndex : pageIndex);
|
|
730
|
-
|
|
731
|
-
if (anchor === "center" || anchor === "centre") //how you can tell an American coded this
|
|
732
|
-
{
|
|
733
|
-
return parseInt(this.getPageData(pidx, "h") / 2, 10);
|
|
734
|
-
}
|
|
735
|
-
else if (anchor === "bottom")
|
|
736
|
-
{
|
|
737
|
-
return parseInt(this.getPageData(pidx, "h") - this.settings.panelHeight / 2, 10);
|
|
738
|
-
}
|
|
739
|
-
else
|
|
740
|
-
{
|
|
741
|
-
return parseInt(this.settings.panelHeight / 2, 10);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
//Same as getYOffset with "left" and "right" as acceptable values instead of "top" and "bottom"
|
|
746
|
-
getXOffset (pageIndex, anchor)
|
|
747
|
-
{
|
|
748
|
-
let pidx = (typeof(pageIndex) === "undefined" ? this.settings.activePageIndex : pageIndex);
|
|
749
|
-
|
|
750
|
-
if (anchor === "left")
|
|
751
|
-
{
|
|
752
|
-
return parseInt(this.settings.panelWidth / 2, 10);
|
|
753
|
-
}
|
|
754
|
-
else if (anchor === "right")
|
|
755
|
-
{
|
|
756
|
-
return parseInt(this.getPageData(pidx, "w") - this.settings.panelWidth / 2, 10);
|
|
757
|
-
}
|
|
758
|
-
else
|
|
759
|
-
{
|
|
760
|
-
return parseInt(this.getPageData(pidx, "w") / 2, 10);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// updates panelHeight/panelWidth on resize
|
|
765
|
-
updatePanelSize ()
|
|
766
|
-
{
|
|
767
|
-
this.viewerState.viewport.invalidate();
|
|
768
|
-
|
|
769
|
-
// FIXME(wabain): This should really only be called after initial load
|
|
770
|
-
if (this.viewerState.renderer)
|
|
771
|
-
{
|
|
772
|
-
this.updateOffsets();
|
|
773
|
-
this.viewerState.renderer.goto(this.settings.activePageIndex, this.viewerState.verticalOffset, this.viewerState.horizontalOffset);
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
return true;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
updateOffsets ()
|
|
780
|
-
{
|
|
781
|
-
const pageOffset = this.viewerState.renderer.layout.getPageToViewportCenterOffset(this.settings.activePageIndex, this.viewerState.viewport);
|
|
782
|
-
|
|
783
|
-
if (pageOffset)
|
|
784
|
-
{
|
|
785
|
-
this.viewerState.horizontalOffset = pageOffset.x;
|
|
786
|
-
this.viewerState.verticalOffset = pageOffset.y;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// Bind mouse events (drag to scroll, double-click)
|
|
791
|
-
bindMouseEvents ()
|
|
792
|
-
{
|
|
793
|
-
// Set drag scroll on the viewport object
|
|
794
|
-
this.viewerState.viewportObject.classList.add('dragscroll');
|
|
795
|
-
|
|
796
|
-
gestureEvents.onDoubleClick(this.viewerState.viewportObject, (event, coords) =>
|
|
797
|
-
{
|
|
798
|
-
debug('Double click at %s, %s', coords.left, coords.top);
|
|
799
|
-
this.viewerState.viewHandler.onDoubleClick(event, coords);
|
|
800
|
-
});
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
onResize ()
|
|
804
|
-
{
|
|
805
|
-
this.updatePanelSize();
|
|
806
|
-
// Cancel any previously-set resize timeouts
|
|
807
|
-
clearTimeout(this.viewerState.resizeTimer);
|
|
808
|
-
|
|
809
|
-
this.viewerState.resizeTimer = setTimeout( () =>
|
|
810
|
-
{
|
|
811
|
-
const pageOffset = this.viewerState.renderer.layout.getPageToViewportCenterOffset(this.settings.activePageIndex, this.viewerState.viewport);
|
|
812
|
-
|
|
813
|
-
if (pageOffset)
|
|
814
|
-
{
|
|
815
|
-
this.reloadViewer({
|
|
816
|
-
goDirectlyTo: this.settings.activePageIndex,
|
|
817
|
-
verticalOffset: pageOffset.y,
|
|
818
|
-
horizontalOffset: pageOffset.x
|
|
819
|
-
});
|
|
820
|
-
}
|
|
821
|
-
else
|
|
822
|
-
{
|
|
823
|
-
this.reloadViewer({
|
|
824
|
-
goDirectlyTo: this.settings.activePageIndex
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
}, 200);
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// Bind touch and orientation change events
|
|
831
|
-
bindTouchEvents ()
|
|
832
|
-
{
|
|
833
|
-
// Block the user from moving the window only if it's not integrated
|
|
834
|
-
if (this.settings.blockMobileMove)
|
|
835
|
-
{
|
|
836
|
-
document.body.addEventListener('touchmove', (event) =>
|
|
837
|
-
{
|
|
838
|
-
const e = event.originalEvent;
|
|
839
|
-
e.preventDefault();
|
|
840
|
-
|
|
841
|
-
return false;
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
// Touch events for swiping in the viewport to scroll pages
|
|
846
|
-
// this.viewerState.viewportObject.addEventListener('scroll', this.scrollFunction.bind(this));
|
|
847
|
-
|
|
848
|
-
gestureEvents.onPinch(this.viewerState.viewportObject, function (event, coords, start, end)
|
|
849
|
-
{
|
|
850
|
-
debug('Pinch %s at %s, %s', end - start, coords.left, coords.top);
|
|
851
|
-
this.viewerState.viewHandler.onPinch(event, coords, start, end);
|
|
852
|
-
});
|
|
853
|
-
|
|
854
|
-
gestureEvents.onDoubleTap(this.viewerState.viewportObject, function (event, coords)
|
|
855
|
-
{
|
|
856
|
-
debug('Double tap at %s, %s', coords.left, coords.top);
|
|
857
|
-
this.viewerState.viewHandler.onDoubleClick(event, coords);
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
// Handle the scroll
|
|
862
|
-
scrollFunction ()
|
|
863
|
-
{
|
|
864
|
-
const previousTopScroll = this.viewerState.viewport.top;
|
|
865
|
-
const previousLeftScroll = this.viewerState.viewport.left;
|
|
866
|
-
|
|
867
|
-
let direction;
|
|
868
|
-
|
|
869
|
-
this.viewerState.viewport.invalidate();
|
|
870
|
-
|
|
871
|
-
const newScrollTop = this.viewerState.viewport.top;
|
|
872
|
-
const newScrollLeft = this.viewerState.viewport.left;
|
|
873
|
-
|
|
874
|
-
if (this.settings.verticallyOriented || this.settings.inGrid)
|
|
875
|
-
direction = newScrollTop - previousTopScroll;
|
|
876
|
-
else
|
|
877
|
-
direction = newScrollLeft - previousLeftScroll;
|
|
878
|
-
|
|
879
|
-
this.viewerState.renderer.adjust();
|
|
880
|
-
|
|
881
|
-
const primaryScroll = (this.settings.verticallyOriented || this.settings.inGrid) ? newScrollTop : newScrollLeft;
|
|
882
|
-
|
|
883
|
-
this.publish("ViewerDidScroll", primaryScroll);
|
|
884
|
-
|
|
885
|
-
if (direction > 0)
|
|
886
|
-
{
|
|
887
|
-
this.publish("ViewerDidScrollDown", primaryScroll);
|
|
888
|
-
}
|
|
889
|
-
else if (direction < 0)
|
|
890
|
-
{
|
|
891
|
-
this.publish("ViewerDidScrollUp", primaryScroll);
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
this.updateOffsets();
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// Binds most of the event handlers (some more in createToolbar)
|
|
898
|
-
handleEvents ()
|
|
899
|
-
{
|
|
900
|
-
// Change the cursor for dragging
|
|
901
|
-
this.viewerState.innerObject.addEventListener('mousedown', () =>
|
|
902
|
-
{
|
|
903
|
-
this.viewerState.innerObject.classList.add('diva-grabbing');
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
this.viewerState.innerObject.addEventListener('mouseup', () =>
|
|
907
|
-
{
|
|
908
|
-
this.viewerState.innerObject.classList.remove('diva-grabbing');
|
|
909
|
-
});
|
|
910
|
-
|
|
911
|
-
this.bindMouseEvents();
|
|
912
|
-
this.viewerState.viewportObject.addEventListener('scroll', this.boundScrollFunction);
|
|
913
|
-
|
|
914
|
-
const upArrowKey = 38, downArrowKey = 40, leftArrowKey = 37, rightArrowKey = 39, spaceKey = 32, pageUpKey = 33, pageDownKey = 34, homeKey = 36, endKey = 35;
|
|
915
|
-
|
|
916
|
-
// Catch the key presses in document
|
|
917
|
-
document.addEventListener('keydown.diva', (event) =>
|
|
918
|
-
{
|
|
919
|
-
if (!this.viewerState.isActiveDiva)
|
|
920
|
-
return true;
|
|
921
|
-
|
|
922
|
-
// Space or page down - go to the next page
|
|
923
|
-
if ((this.settings.enableSpaceScroll && !event.shiftKey && event.keyCode === spaceKey) || (this.settings.enableKeyScroll && event.keyCode === pageDownKey))
|
|
924
|
-
{
|
|
925
|
-
this.viewerState.viewport.top += this.settings.panelHeight;
|
|
926
|
-
return false;
|
|
927
|
-
}
|
|
928
|
-
else if (!this.settings.enableSpaceScroll && event.keyCode === spaceKey)
|
|
929
|
-
{
|
|
930
|
-
event.preventDefault();
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
if (this.settings.enableKeyScroll)
|
|
934
|
-
{
|
|
935
|
-
// Don't steal keyboard shortcuts (metaKey = command [OS X], super [Win/Linux])
|
|
936
|
-
if (event.shiftKey || event.ctrlKey || event.metaKey)
|
|
937
|
-
return true;
|
|
938
|
-
|
|
939
|
-
switch (event.keyCode)
|
|
940
|
-
{
|
|
941
|
-
case pageUpKey:
|
|
942
|
-
// Page up - go to the previous page
|
|
943
|
-
this.viewerState.viewport.top -= this.settings.panelHeight;
|
|
944
|
-
return false;
|
|
945
|
-
|
|
946
|
-
case upArrowKey:
|
|
947
|
-
// Up arrow - scroll up
|
|
948
|
-
this.viewerState.viewport.top -= this.settings.arrowScrollAmount;
|
|
949
|
-
return false;
|
|
950
|
-
|
|
951
|
-
case downArrowKey:
|
|
952
|
-
// Down arrow - scroll down
|
|
953
|
-
this.viewerState.viewport.top += this.settings.arrowScrollAmount;
|
|
954
|
-
return false;
|
|
955
|
-
|
|
956
|
-
case leftArrowKey:
|
|
957
|
-
// Left arrow - scroll left
|
|
958
|
-
this.viewerState.viewport.left -= this.settings.arrowScrollAmount;
|
|
959
|
-
return false;
|
|
960
|
-
|
|
961
|
-
case rightArrowKey:
|
|
962
|
-
// Right arrow - scroll right
|
|
963
|
-
this.viewerState.viewport.left += this.settings.arrowScrollAmount;
|
|
964
|
-
return false;
|
|
965
|
-
|
|
966
|
-
case homeKey:
|
|
967
|
-
// Home key - go to the beginning of the document
|
|
968
|
-
this.viewerState.viewport.top = 0;
|
|
969
|
-
return false;
|
|
970
|
-
|
|
971
|
-
case endKey:
|
|
972
|
-
// End key - go to the end of the document
|
|
973
|
-
// Count on the viewport coordinate value being normalized
|
|
974
|
-
if (this.settings.verticallyOriented)
|
|
975
|
-
this.viewerState.viewport.top = Infinity;
|
|
976
|
-
else
|
|
977
|
-
this.viewerState.viewport.left = Infinity;
|
|
978
|
-
|
|
979
|
-
return false;
|
|
980
|
-
|
|
981
|
-
default:
|
|
982
|
-
return true;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
return true;
|
|
986
|
-
});
|
|
987
|
-
|
|
988
|
-
diva.Events.subscribe('ViewerDidTerminate', function()
|
|
989
|
-
{
|
|
990
|
-
document.removeEventListener('keydown.diva');
|
|
991
|
-
}, this.settings.ID);
|
|
992
|
-
|
|
993
|
-
// this.bindTouchEvents();
|
|
994
|
-
|
|
995
|
-
// Handle window resizing events
|
|
996
|
-
window.addEventListener('resize', this.onResize.bind(this), false);
|
|
997
|
-
|
|
998
|
-
diva.Events.subscribe('ViewerDidTerminate', function()
|
|
999
|
-
{
|
|
1000
|
-
window.removeEventListener('resize', this.onResize, false);
|
|
1001
|
-
}, this.settings.ID);
|
|
1002
|
-
|
|
1003
|
-
// Handle orientation change separately
|
|
1004
|
-
if ('onorientationchange' in window)
|
|
1005
|
-
{
|
|
1006
|
-
window.addEventListener('orientationchange', this.onResize, false);
|
|
1007
|
-
|
|
1008
|
-
diva.Events.subscribe('ViewerDidTerminate', function()
|
|
1009
|
-
{
|
|
1010
|
-
window.removeEventListener('orientationchange', this.onResize, false);
|
|
1011
|
-
}, this.settings.ID);
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
diva.Events.subscribe('PanelSizeDidChange', this.updatePanelSize, this.settings.ID);
|
|
1015
|
-
|
|
1016
|
-
// Clear page and resize timeouts when the viewer is destroyed
|
|
1017
|
-
diva.Events.subscribe('ViewerDidTerminate', () =>
|
|
1018
|
-
{
|
|
1019
|
-
if (this.viewerState.renderer)
|
|
1020
|
-
this.viewerState.renderer.destroy();
|
|
1021
|
-
|
|
1022
|
-
clearTimeout(this.viewerState.resizeTimer);
|
|
1023
|
-
}, this.settings.ID);
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
initPlugins ()
|
|
1027
|
-
{
|
|
1028
|
-
if (!this.settings.hasOwnProperty('plugins'))
|
|
1029
|
-
return null;
|
|
1030
|
-
|
|
1031
|
-
this.viewerState.pluginInstances = this.settings.plugins.map( (plugin) =>
|
|
1032
|
-
{
|
|
1033
|
-
const p = new plugin(this);
|
|
1034
|
-
|
|
1035
|
-
if (p.isPageTool)
|
|
1036
|
-
this.viewerState.pageTools.push(p);
|
|
1037
|
-
|
|
1038
|
-
return p;
|
|
1039
|
-
});
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
showThrobber ()
|
|
1043
|
-
{
|
|
1044
|
-
this.hideThrobber();
|
|
1045
|
-
|
|
1046
|
-
this.viewerState.throbberTimeoutID = setTimeout( () =>
|
|
1047
|
-
{
|
|
1048
|
-
let thb = document.getElementById(this.settings.selector + 'throbber');
|
|
1049
|
-
if (thb) thb.style.display = 'block';
|
|
1050
|
-
}, this.settings.throbberTimeout);
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
hideThrobber ()
|
|
1054
|
-
{
|
|
1055
|
-
// Clear the timeout, if it hasn't executed yet
|
|
1056
|
-
clearTimeout(this.viewerState.throbberTimeoutID);
|
|
1057
|
-
|
|
1058
|
-
let thb = document.getElementById(this.settings.selector + 'throbber');
|
|
1059
|
-
// Hide the throbber if it has already executed
|
|
1060
|
-
if (thb) thb.style.display = 'none';
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
showError (message)
|
|
1064
|
-
{
|
|
1065
|
-
const errorElement = elt('div', this.elemAttrs('error'), [
|
|
1066
|
-
elt('button', this.elemAttrs('error-close', {'aria-label': 'Close dialog'})),
|
|
1067
|
-
elt('p',
|
|
1068
|
-
elt('strong', 'Error')
|
|
1069
|
-
),
|
|
1070
|
-
elt('div', message)
|
|
1071
|
-
]);
|
|
1072
|
-
|
|
1073
|
-
this.viewerState.outerObject.appendChild(errorElement);
|
|
1074
|
-
|
|
1075
|
-
//bind dialog close button
|
|
1076
|
-
document.querySelector(this.settings.selector + 'error-close').addEventListener('click', () =>
|
|
1077
|
-
{
|
|
1078
|
-
errorElement.parentNode.removeChild(errorElement);
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
setManifest (manifest, loadOptions)
|
|
1083
|
-
{
|
|
1084
|
-
this.viewerState.manifest = manifest;
|
|
1085
|
-
|
|
1086
|
-
this.hideThrobber();
|
|
1087
|
-
|
|
1088
|
-
// Convenience value
|
|
1089
|
-
this.viewerState.numPages = this.settings.manifest.pages.length;
|
|
1090
|
-
|
|
1091
|
-
this.optionsValidator.validate(this.viewerState.options);
|
|
1092
|
-
|
|
1093
|
-
this.publish('NumberOfPagesDidChange', this.settings.numPages);
|
|
1094
|
-
|
|
1095
|
-
// Calculate the horizontal and vertical inter-page padding based on the dimensions of the average zoom level
|
|
1096
|
-
if (this.settings.adaptivePadding > 0)
|
|
1097
|
-
{
|
|
1098
|
-
const z = Math.floor((this.settings.minZoomLevel + this.settings.maxZoomLevel) / 2);
|
|
1099
|
-
this.viewerState.horizontalPadding = parseInt(this.settings.manifest.getAverageWidth(z) * this.settings.adaptivePadding, 10);
|
|
1100
|
-
this.viewerState.verticalPadding = parseInt(this.settings.manifest.getAverageHeight(z) * this.settings.adaptivePadding, 10);
|
|
1101
|
-
}
|
|
1102
|
-
else
|
|
1103
|
-
{
|
|
1104
|
-
// It's less than or equal to 0; use fixedPadding instead
|
|
1105
|
-
this.viewerState.horizontalPadding = this.settings.fixedPadding;
|
|
1106
|
-
this.viewerState.verticalPadding = this.settings.fixedPadding;
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
// Make sure the vertical padding is at least 40, if plugin icons are enabled
|
|
1110
|
-
if (this.viewerState.pageTools.length)
|
|
1111
|
-
{
|
|
1112
|
-
this.viewerState.verticalPadding = Math.max(40, this.viewerState.verticalPadding);
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
// If we detect a viewingHint of 'paged' in the manifest or sequence, enable book view by default
|
|
1116
|
-
if (this.settings.manifest.paged)
|
|
1117
|
-
{
|
|
1118
|
-
this.viewerState.options.inBookLayout = true;
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
// Plugin setup hooks should be bound to the ObjectDidLoad event
|
|
1122
|
-
this.publish('ObjectDidLoad', this.settings);
|
|
1123
|
-
|
|
1124
|
-
// Adjust the document panel dimensions
|
|
1125
|
-
this.updatePanelSize();
|
|
1126
|
-
|
|
1127
|
-
let needsXCoord, needsYCoord;
|
|
1128
|
-
|
|
1129
|
-
let anchoredVertically = false;
|
|
1130
|
-
let anchoredHorizontally = false;
|
|
1131
|
-
|
|
1132
|
-
// NB: `==` here will check both null and undefined
|
|
1133
|
-
if (loadOptions.goDirectlyTo == null)
|
|
1134
|
-
{
|
|
1135
|
-
loadOptions.goDirectlyTo = this.settings.goDirectlyTo;
|
|
1136
|
-
needsXCoord = needsYCoord = true;
|
|
1137
|
-
}
|
|
1138
|
-
else
|
|
1139
|
-
{
|
|
1140
|
-
needsXCoord = loadOptions.horizontalOffset == null || isNaN(loadOptions.horizontalOffset);
|
|
1141
|
-
needsYCoord = loadOptions.verticalOffset == null || isNaN(loadOptions.verticalOffset);
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
// Set default values for the horizontal and vertical offsets
|
|
1145
|
-
if (needsXCoord)
|
|
1146
|
-
{
|
|
1147
|
-
// FIXME: What if inBookLayout/verticallyOriented is changed by loadOptions?
|
|
1148
|
-
if (loadOptions.goDirectlyTo === 0 && this.settings.inBookLayout && this.settings.verticallyOriented)
|
|
1149
|
-
{
|
|
1150
|
-
// if in book layout, center the first opening by default
|
|
1151
|
-
loadOptions.horizontalOffset = this.viewerState.horizontalPadding;
|
|
1152
|
-
}
|
|
1153
|
-
else
|
|
1154
|
-
{
|
|
1155
|
-
anchoredHorizontally = true;
|
|
1156
|
-
loadOptions.horizontalOffset = this.getXOffset(loadOptions.goDirectlyTo, "center");
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
if (needsYCoord)
|
|
1161
|
-
{
|
|
1162
|
-
anchoredVertically = true;
|
|
1163
|
-
loadOptions.verticalOffset = this.getYOffset(loadOptions.goDirectlyTo, "top");
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
this.reloadViewer(loadOptions);
|
|
1167
|
-
|
|
1168
|
-
//prep dimensions one last time now that pages have loaded
|
|
1169
|
-
this.updatePanelSize();
|
|
1170
|
-
|
|
1171
|
-
if (this.settings.enableAutoTitle)
|
|
1172
|
-
{
|
|
1173
|
-
let title = document.getElementById(this.settings.selector + 'title');
|
|
1174
|
-
|
|
1175
|
-
if (title)
|
|
1176
|
-
{
|
|
1177
|
-
title.innerHTML = this.settings.manifest.itemTitle;
|
|
1178
|
-
}
|
|
1179
|
-
else
|
|
1180
|
-
{
|
|
1181
|
-
this.settings.parentObject.insertBefore(
|
|
1182
|
-
elt('div', this.elemAttrs('title'), [this.settings.manifest.itemTitle]),
|
|
1183
|
-
this.settings.parentObject.firstChild
|
|
1184
|
-
);
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
// FIXME: This is a hack to ensure that the outerElement scrollbars are taken into account
|
|
1189
|
-
if (this.settings.verticallyOriented)
|
|
1190
|
-
this.viewerState.innerElement.style.minWidth = this.settings.panelWidth + 'px';
|
|
1191
|
-
else
|
|
1192
|
-
this.viewerState.innerElement.style.minHeight = this.settings.panelHeight + 'px';
|
|
1193
|
-
|
|
1194
|
-
// FIXME: If the page was supposed to be positioned relative to the viewport we need to
|
|
1195
|
-
// recalculate it to take into account the scrollbars
|
|
1196
|
-
if (anchoredVertically || anchoredHorizontally)
|
|
1197
|
-
{
|
|
1198
|
-
if (anchoredVertically)
|
|
1199
|
-
this.viewerState.verticalOffset = this.getYOffset(this.settings.activePageIndex, "top");
|
|
1200
|
-
|
|
1201
|
-
if (anchoredHorizontally)
|
|
1202
|
-
this.viewerState.horizontalOffset = this.getXOffset(this.settings.activePageIndex, "center");
|
|
1203
|
-
|
|
1204
|
-
this.viewerState.renderer.goto(this.settings.activePageIndex, this.viewerState.verticalOffset, this.viewerState.horizontalOffset);
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
// signal that everything should be set up and ready to go.
|
|
1208
|
-
this.viewerState.loaded = true;
|
|
1209
|
-
|
|
1210
|
-
this.publish("ViewerDidLoad", this.settings);
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
publish (event)
|
|
1214
|
-
{
|
|
1215
|
-
const args = Array.prototype.slice.call(arguments, 1);
|
|
1216
|
-
diva.Events.publish(event, args, this.publicInstance);
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
getSettings ()
|
|
1220
|
-
{
|
|
1221
|
-
return this.settings;
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
// Temporary accessor for the state of the viewer core
|
|
1225
|
-
// TODO: Replace this with a more restricted view of whatever needs
|
|
1226
|
-
// be exposed through settings for backwards compat
|
|
1227
|
-
getInternalState ()
|
|
1228
|
-
{
|
|
1229
|
-
return this.viewerState;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
getPublicInstance ()
|
|
1233
|
-
{
|
|
1234
|
-
return this.publicInstance;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
getPageTools ()
|
|
1238
|
-
{
|
|
1239
|
-
return this.viewerState.pageTools;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
getCurrentLayout ()
|
|
1243
|
-
{
|
|
1244
|
-
return this.viewerState.renderer ? this.viewerState.renderer.layout : null;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
/** Get a copy of the current viewport dimensions */
|
|
1248
|
-
getViewport ()
|
|
1249
|
-
{
|
|
1250
|
-
const viewport = this.viewerState.viewport;
|
|
1251
|
-
|
|
1252
|
-
return {
|
|
1253
|
-
top: viewport.top,
|
|
1254
|
-
left: viewport.left,
|
|
1255
|
-
bottom: viewport.bottom,
|
|
1256
|
-
right: viewport.right,
|
|
1257
|
-
|
|
1258
|
-
width: viewport.width,
|
|
1259
|
-
height: viewport.height
|
|
1260
|
-
};
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
addPageOverlay (overlay)
|
|
1264
|
-
{
|
|
1265
|
-
this.viewerState.pageOverlays.addOverlay(overlay);
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
removePageOverlay (overlay)
|
|
1269
|
-
{
|
|
1270
|
-
this.viewerState.pageOverlays.removeOverlay(overlay);
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
getPageRegion (pageIndex, options)
|
|
1274
|
-
{
|
|
1275
|
-
const layout = this.viewerState.renderer.layout;
|
|
1276
|
-
const region = layout.getPageRegion(pageIndex, options);
|
|
1277
|
-
|
|
1278
|
-
if (options && options.incorporateViewport)
|
|
1279
|
-
{
|
|
1280
|
-
const secondaryDim = this.settings.verticallyOriented ? 'width' : 'height';
|
|
1281
|
-
|
|
1282
|
-
if (this.viewerState.viewport[secondaryDim] > layout.dimensions[secondaryDim])
|
|
1283
|
-
{
|
|
1284
|
-
const docOffset = (this.viewerState.viewport[secondaryDim] - layout.dimensions[secondaryDim]) / 2;
|
|
1285
|
-
|
|
1286
|
-
if (this.settings.verticallyOriented)
|
|
1287
|
-
{
|
|
1288
|
-
return {
|
|
1289
|
-
top: region.top,
|
|
1290
|
-
bottom: region.bottom,
|
|
1291
|
-
|
|
1292
|
-
left: region.left + docOffset,
|
|
1293
|
-
right: region.right + docOffset
|
|
1294
|
-
};
|
|
1295
|
-
}
|
|
1296
|
-
else
|
|
1297
|
-
{
|
|
1298
|
-
return {
|
|
1299
|
-
top: region.top + docOffset,
|
|
1300
|
-
bottom: region.bottom + docOffset,
|
|
1301
|
-
|
|
1302
|
-
left: region.left,
|
|
1303
|
-
right: region.right
|
|
1304
|
-
};
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
return region;
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
getPagePositionAtViewportOffset (coords)
|
|
1313
|
-
{
|
|
1314
|
-
const docCoords = {
|
|
1315
|
-
left: coords.left + this.viewerState.viewport.left,
|
|
1316
|
-
top: coords.top + this.viewerState.viewport.top
|
|
1317
|
-
};
|
|
1318
|
-
|
|
1319
|
-
const renderedPages = this.viewerState.renderer.getRenderedPages();
|
|
1320
|
-
const pageCount = renderedPages.length;
|
|
1321
|
-
|
|
1322
|
-
// Find the page on which the coords occur
|
|
1323
|
-
for (let i=0; i < pageCount; i++)
|
|
1324
|
-
{
|
|
1325
|
-
const pageIndex = renderedPages[i];
|
|
1326
|
-
const region = this.viewerState.renderer.layout.getPageRegion(pageIndex);
|
|
1327
|
-
|
|
1328
|
-
if (region.left <= docCoords.left && region.right >= docCoords.left &&
|
|
1329
|
-
region.top <= docCoords.top && region.bottom >= docCoords.top)
|
|
1330
|
-
{
|
|
1331
|
-
return {
|
|
1332
|
-
anchorPage: pageIndex,
|
|
1333
|
-
offset: {
|
|
1334
|
-
left: docCoords.left - region.left,
|
|
1335
|
-
top: docCoords.top - region.top
|
|
1336
|
-
}
|
|
1337
|
-
};
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
// Fall back to current page
|
|
1342
|
-
// FIXME: Would be better to use the closest page or something
|
|
1343
|
-
const currentRegion = this.viewerState.renderer.layout.getPageRegion(this.settings.activePageIndex);
|
|
1344
|
-
|
|
1345
|
-
return {
|
|
1346
|
-
anchorPage: this.settings.activePageIndex,
|
|
1347
|
-
offset: {
|
|
1348
|
-
left: docCoords.left - currentRegion.left,
|
|
1349
|
-
top: docCoords.top - currentRegion.top
|
|
1350
|
-
}
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
// setManifest (manifest, loadOptions)
|
|
1355
|
-
// {
|
|
1356
|
-
// setManifest(manifest, loadOptions || {});
|
|
1357
|
-
// }
|
|
1358
|
-
|
|
1359
|
-
/**
|
|
1360
|
-
* Set the current page to the given index, firing VisiblePageDidChange
|
|
1361
|
-
*
|
|
1362
|
-
* @param pageIndex
|
|
1363
|
-
*/
|
|
1364
|
-
setCurrentPages (activePage, visiblePages)
|
|
1365
|
-
{
|
|
1366
|
-
if (!arraysEqual(this.viewerState.currentPageIndices, visiblePages))
|
|
1367
|
-
{
|
|
1368
|
-
this.viewerState.currentPageIndices = visiblePages;
|
|
1369
|
-
if (this.viewerState.activePageIndex !== activePage)
|
|
1370
|
-
{
|
|
1371
|
-
this.viewerState.activePageIndex = activePage;
|
|
1372
|
-
this.publish("ActivePageDidChange", activePage);
|
|
1373
|
-
}
|
|
1374
|
-
this.publish("VisiblePageDidChange", visiblePages);
|
|
1375
|
-
|
|
1376
|
-
// Publish an event if the page we're switching to has other images.
|
|
1377
|
-
if (this.viewerState.manifest.pages[activePage].otherImages.length > 0)
|
|
1378
|
-
this.publish('VisiblePageHasAlternateViews', activePage);
|
|
1379
|
-
}
|
|
1380
|
-
else if (this.viewerState.activePageIndex !== activePage)
|
|
1381
|
-
{
|
|
1382
|
-
this.viewerState.activePageIndex = activePage;
|
|
1383
|
-
this.publish("ActivePageDidChange", activePage);
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
function arraysEqual (a, b)
|
|
1387
|
-
{
|
|
1388
|
-
if (a.length !== b.length)
|
|
1389
|
-
return false;
|
|
1390
|
-
|
|
1391
|
-
for (let i = 0, len = a.length; i < len; i++)
|
|
1392
|
-
{
|
|
1393
|
-
if (a[i] !== b[i])
|
|
1394
|
-
return false;
|
|
1395
|
-
}
|
|
1396
|
-
return true;
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
getPageName (pageIndex)
|
|
1401
|
-
{
|
|
1402
|
-
return this.viewerState.manifest.pages[pageIndex].f;
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
reload (newOptions)
|
|
1406
|
-
{
|
|
1407
|
-
this.reloadViewer(newOptions);
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
zoom (zoomLevel, focalPoint)
|
|
1411
|
-
{
|
|
1412
|
-
return this.handleZoom(zoomLevel, focalPoint);
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
enableScrollable ()
|
|
1416
|
-
{
|
|
1417
|
-
if (!this.viewerState.isScrollable)
|
|
1418
|
-
{
|
|
1419
|
-
this.bindMouseEvents();
|
|
1420
|
-
this.enableDragScrollable();
|
|
1421
|
-
this.viewerState.options.enableKeyScroll = this.viewerState.initialKeyScroll;
|
|
1422
|
-
this.viewerState.options.enableSpaceScroll = this.viewerState.initialSpaceScroll;
|
|
1423
|
-
this.viewerState.viewportElement.style.overflow = 'auto';
|
|
1424
|
-
this.viewerState.isScrollable = true;
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
enableDragScrollable ()
|
|
1429
|
-
{
|
|
1430
|
-
if (this.viewerState.viewportObject.hasAttribute('nochilddrag'))
|
|
1431
|
-
this.viewerState.viewportObject.removeAttribute('nochilddrag');
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
disableScrollable ()
|
|
1435
|
-
{
|
|
1436
|
-
if (this.viewerState.isScrollable)
|
|
1437
|
-
{
|
|
1438
|
-
// block dragging
|
|
1439
|
-
this.disableDragScrollable();
|
|
1440
|
-
|
|
1441
|
-
// block double-click zooming
|
|
1442
|
-
this.viewerState.outerObject.dblclick = null;
|
|
1443
|
-
this.viewerState.outerObject.contextmenu = null;
|
|
1444
|
-
|
|
1445
|
-
// disable all other scrolling actions
|
|
1446
|
-
this.viewerState.viewportElement.style.overflow = 'hidden';
|
|
1447
|
-
|
|
1448
|
-
// block scrolling keys behavior, respecting initial scroll settings
|
|
1449
|
-
this.viewerState.initialKeyScroll = this.settings.enableKeyScroll;
|
|
1450
|
-
this.viewerState.initialSpaceScroll = this.settings.enableSpaceScroll;
|
|
1451
|
-
this.viewerState.options.enableKeyScroll = false;
|
|
1452
|
-
this.viewerState.options.enableSpaceScroll = false;
|
|
1453
|
-
|
|
1454
|
-
this.viewerState.isScrollable = false;
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
disableDragScrollable ()
|
|
1459
|
-
{
|
|
1460
|
-
if (!this.viewerState.viewportObject.hasAttribute('nochilddrag'))
|
|
1461
|
-
this.viewerState.viewportObject.setAttribute('nochilddrag', "");
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
// isValidOption (key, value)
|
|
1465
|
-
// {
|
|
1466
|
-
// return isValidOption(key, value);
|
|
1467
|
-
// }
|
|
1468
|
-
|
|
1469
|
-
// getXOffset (pageIndex, xAnchor)
|
|
1470
|
-
// {
|
|
1471
|
-
// return getXOffset(pageIndex, xAnchor);
|
|
1472
|
-
// }
|
|
1473
|
-
|
|
1474
|
-
// getYOffset (pageIndex, yAnchor)
|
|
1475
|
-
// {
|
|
1476
|
-
// return getYOffset(pageIndex, yAnchor);
|
|
1477
|
-
// }
|
|
1478
|
-
|
|
1479
|
-
// this.publish = publish;
|
|
1480
|
-
|
|
1481
|
-
clear ()
|
|
1482
|
-
{
|
|
1483
|
-
this.clearViewer();
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
setPendingManifestRequest (pendingManifestRequest)
|
|
1487
|
-
{
|
|
1488
|
-
this.viewerState.pendingManifestRequest = pendingManifestRequest;
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
destroy ()
|
|
1492
|
-
{
|
|
1493
|
-
// Useful event to access elements in diva before they get destroyed. Used by the highlight plugin.
|
|
1494
|
-
this.publish('ViewerWillTerminate', this.settings);
|
|
1495
|
-
|
|
1496
|
-
// Cancel any pending request retrieving a manifest
|
|
1497
|
-
if (this.settings.pendingManifestRequest)
|
|
1498
|
-
this.settings.pendingManifestRequest.abort();
|
|
1499
|
-
|
|
1500
|
-
// Removes the hide-scrollbar class from the body
|
|
1501
|
-
document.body.removeClass('diva-hide-scrollbar');
|
|
1502
|
-
|
|
1503
|
-
// Empty the parent container and remove any diva-related data
|
|
1504
|
-
this.settings.parentObject.parent().empty().removeData('diva');
|
|
1505
|
-
|
|
1506
|
-
// Remove any additional styling on the parent element
|
|
1507
|
-
this.settings.parentObject.parent().removeAttr('style').removeAttr('class');
|
|
1508
|
-
|
|
1509
|
-
this.publish('ViewerDidTerminate', this.settings);
|
|
1510
|
-
|
|
1511
|
-
// Clear the Events cache
|
|
1512
|
-
diva.Events.unsubscribeAll(this.settings.ID);
|
|
1513
|
-
}
|
|
1514
|
-
}
|