kfb-view 3.0.8 → 3.0.9

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.
Files changed (38) hide show
  1. package/lib/kfb-view.js +1 -1
  2. package/lib/kfb-view.js.LICENSE.txt +3 -3
  3. package/package.json +3 -2
  4. package/src/components/area/index.js +38 -48
  5. package/src/components/board/index.js +1 -1
  6. package/src/components/common/common.js +0 -67
  7. package/src/plugin/openseadragon/openseadragon.js +667 -126
  8. package/src/util/calculate.js +79 -35
  9. package/src/util/imageData.js +0 -5
  10. package/src/view.js +6 -6
  11. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  12. package/.idea/git_toolbox_prj.xml +0 -20
  13. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  14. package/.idea/inspectionProfiles/profiles_settings.xml +0 -5
  15. package/.idea/kfb-view.iml +0 -12
  16. package/.idea/misc.xml +0 -86
  17. package/.idea/modules.xml +0 -8
  18. package/.idea/vcs.xml +0 -6
  19. package/.idea/watcherTasks.xml +0 -4
  20. package/.idea/workspace.xml +0 -874
  21. package/config/utils.js +0 -77
  22. package/config/webpack.base.conf.js +0 -95
  23. package/config/webpack.dev.conf.js +0 -80
  24. package/config/webpack.lib.conf.js +0 -92
  25. package/config/webpack.prod.conf.js +0 -102
  26. package/config/webpack.test.conf.js +0 -0
  27. package/example/index.js +0 -547
  28. package/example/label/check.svg +0 -8
  29. package/example/label/check_empty.svg +0 -9
  30. package/example/label/cross.svg +0 -6
  31. package/example/label/cross_empty.svg +0 -6
  32. package/example/label/delete.svg +0 -8
  33. package/example/label/delete_empty.svg +0 -8
  34. package/example/label/hasAudit.svg +0 -26
  35. package/example/style/index.css +0 -153
  36. package/example/worker/canvas.worker.js +0 -28
  37. package/test.html +0 -246
  38. package/yarn.lock +0 -7508
@@ -1,6 +1,6 @@
1
- //! openseadragon 4.0.0
2
- //! Built on 2022-12-16
3
- //! Git commit: v4.0.0-0-8e6196a
1
+ //! openseadragon 4.1.0
2
+ //! Built on 2023-05-25
3
+ //! Git commit: v4.1.0-0-8849681
4
4
  //! http://openseadragon.github.io
5
5
  //! License: http://openseadragon.github.io/license/
6
6
 
@@ -87,14 +87,16 @@
87
87
  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
88
88
  */
89
89
 
90
+
90
91
  /**
91
92
  * @namespace OpenSeadragon
92
- * @version openseadragon 4.0.0
93
+ * @version openseadragon 4.1.0
93
94
  * @classdesc The root namespace for OpenSeadragon. All utility methods
94
95
  * and classes are defined on or below this namespace.
95
96
  *
96
97
  */
97
98
 
99
+
98
100
  // Typedefs
99
101
 
100
102
  /**
@@ -499,6 +501,12 @@
499
501
  * @property {Number} [timeout=30000]
500
502
  * The max number of milliseconds that an image job may take to complete.
501
503
  *
504
+ * @property {Number} [tileRetryMax=0]
505
+ * The max number of retries when a tile download fails. By default it's 0, so retries are disabled.
506
+ *
507
+ * @property {Number} [tileRetryDelay=2500]
508
+ * Milliseconds to wait after each tile retry if tileRetryMax is set.
509
+ *
502
510
  * @property {Boolean} [useCanvas=true]
503
511
  * Set to false to not use an HTML canvas element for image rendering even if canvas is supported.
504
512
  *
@@ -563,50 +571,50 @@
563
571
  * viewing the first image and the 'next' button will wrap to the first
564
572
  * image when viewing the last image.
565
573
  *
566
- * @property {String} zoomInButton
567
- * Set the id of the custom 'Zoom in' button to use.
574
+ *@property {String|Element} zoomInButton
575
+ * Set the id or element of the custom 'Zoom in' button to use.
568
576
  * This is useful to have a custom button anywhere in the web page.<br>
569
577
  * To only change the button images, consider using
570
578
  * {@link OpenSeadragon.Options.navImages}
571
579
  *
572
- * @property {String} zoomOutButton
573
- * Set the id of the custom 'Zoom out' button to use.
580
+ * @property {String|Element} zoomOutButton
581
+ * Set the id or element of the custom 'Zoom out' button to use.
574
582
  * This is useful to have a custom button anywhere in the web page.<br>
575
583
  * To only change the button images, consider using
576
584
  * {@link OpenSeadragon.Options.navImages}
577
585
  *
578
- * @property {String} homeButton
579
- * Set the id of the custom 'Go home' button to use.
586
+ * @property {String|Element} homeButton
587
+ * Set the id or element of the custom 'Go home' button to use.
580
588
  * This is useful to have a custom button anywhere in the web page.<br>
581
589
  * To only change the button images, consider using
582
590
  * {@link OpenSeadragon.Options.navImages}
583
591
  *
584
- * @property {String} fullPageButton
585
- * Set the id of the custom 'Toggle full page' button to use.
592
+ * @property {String|Element} fullPageButton
593
+ * Set the id or element of the custom 'Toggle full page' button to use.
586
594
  * This is useful to have a custom button anywhere in the web page.<br>
587
595
  * To only change the button images, consider using
588
596
  * {@link OpenSeadragon.Options.navImages}
589
597
  *
590
- * @property {String} rotateLeftButton
591
- * Set the id of the custom 'Rotate left' button to use.
598
+ * @property {String|Element} rotateLeftButton
599
+ * Set the id or element of the custom 'Rotate left' button to use.
592
600
  * This is useful to have a custom button anywhere in the web page.<br>
593
601
  * To only change the button images, consider using
594
602
  * {@link OpenSeadragon.Options.navImages}
595
603
  *
596
- * @property {String} rotateRightButton
597
- * Set the id of the custom 'Rotate right' button to use.
604
+ * @property {String|Element} rotateRightButton
605
+ * Set the id or element of the custom 'Rotate right' button to use.
598
606
  * This is useful to have a custom button anywhere in the web page.<br>
599
607
  * To only change the button images, consider using
600
608
  * {@link OpenSeadragon.Options.navImages}
601
609
  *
602
- * @property {String} previousButton
603
- * Set the id of the custom 'Previous page' button to use.
610
+ * @property {String|Element} previousButton
611
+ * Set the id or element of the custom 'Previous page' button to use.
604
612
  * This is useful to have a custom button anywhere in the web page.<br>
605
613
  * To only change the button images, consider using
606
614
  * {@link OpenSeadragon.Options.navImages}
607
615
  *
608
- * @property {String} nextButton
609
- * Set the id of the custom 'Next page' button to use.
616
+ * @property {String|Element} nextButton
617
+ * Set the id or element of the custom 'Next page' button to use.
610
618
  * This is useful to have a custom button anywhere in the web page.<br>
611
619
  * To only change the button images, consider using
612
620
  * {@link OpenSeadragon.Options.navImages}
@@ -805,6 +813,7 @@ function OpenSeadragon(options) {
805
813
 
806
814
  (function($) {
807
815
 
816
+
808
817
  /**
809
818
  * The OpenSeadragon version.
810
819
  *
@@ -816,12 +825,13 @@ function OpenSeadragon(options) {
816
825
  * @since 1.0.0
817
826
  */
818
827
  $.version = {
819
- versionStr: '4.0.0',
828
+ versionStr: '4.1.0',
820
829
  major: parseInt('4', 10),
821
- minor: parseInt('0', 10),
830
+ minor: parseInt('1', 10),
822
831
  revision: parseInt('0', 10),
823
832
  };
824
833
 
834
+
825
835
  /**
826
836
  * Taken from jquery 1.6.1
827
837
  * [[Class]] -> type pairs
@@ -832,6 +842,8 @@ function OpenSeadragon(options) {
832
842
  '[object Number]': 'number',
833
843
  '[object String]': 'string',
834
844
  '[object Function]': 'function',
845
+ '[object AsyncFunction]': 'function',
846
+ '[object Promise]': 'promise',
835
847
  '[object Array]': 'array',
836
848
  '[object Date]': 'date',
837
849
  '[object RegExp]': 'regexp',
@@ -861,6 +873,7 @@ function OpenSeadragon(options) {
861
873
  return $.type(obj) === 'array';
862
874
  };
863
875
 
876
+
864
877
  /**
865
878
  * A crude way of determining if an object is a window.
866
879
  * Taken from jQuery 1.6.1
@@ -872,6 +885,7 @@ function OpenSeadragon(options) {
872
885
  return obj && typeof obj === 'object' && 'setInterval' in obj;
873
886
  };
874
887
 
888
+
875
889
  /**
876
890
  * Taken from jQuery 1.6.1
877
891
  * @function type
@@ -884,6 +898,7 @@ function OpenSeadragon(options) {
884
898
  class2type[toString.call(obj)] || 'object';
885
899
  };
886
900
 
901
+
887
902
  /**
888
903
  * Taken from jQuery 1.6.1
889
904
  * @function isPlainObject
@@ -917,6 +932,7 @@ function OpenSeadragon(options) {
917
932
  return lastKey === undefined || hasOwn.call(obj, lastKey);
918
933
  };
919
934
 
935
+
920
936
  /**
921
937
  * Taken from jQuery 1.6.1
922
938
  * @function isEmptyObject
@@ -1355,6 +1371,8 @@ function OpenSeadragon(options) {
1355
1371
  maxImageCacheCount: 200,
1356
1372
  timeout: 30000,
1357
1373
  useCanvas: true, // Use canvas element for drawing if available
1374
+ tileRetryMax: 0,
1375
+ tileRetryDelay: 2500,
1358
1376
 
1359
1377
  //INTERFACE RESOURCE SETTINGS
1360
1378
  prefixUrl: '/images/',
@@ -1431,6 +1449,7 @@ function OpenSeadragon(options) {
1431
1449
 
1432
1450
  },
1433
1451
 
1452
+
1434
1453
  /**
1435
1454
  * TODO: get rid of this. I can't see how it's required at all. Looks
1436
1455
  * like an early legacy code artifact.
@@ -1439,6 +1458,7 @@ function OpenSeadragon(options) {
1439
1458
  */
1440
1459
  SIGNAL: '----seadragon----',
1441
1460
 
1461
+
1442
1462
  /**
1443
1463
  * Returns a function which invokes the method as if it were a method belonging to the object.
1444
1464
  * @function
@@ -1456,6 +1476,7 @@ function OpenSeadragon(options) {
1456
1476
  };
1457
1477
  },
1458
1478
 
1479
+
1459
1480
  /**
1460
1481
  * An enumeration of Browser vendors.
1461
1482
  * @static
@@ -1528,6 +1549,7 @@ function OpenSeadragon(options) {
1528
1549
  return element;
1529
1550
  },
1530
1551
 
1552
+
1531
1553
  /**
1532
1554
  * Determines the position of the upper-left corner of the element.
1533
1555
  * @function
@@ -1560,6 +1582,7 @@ function OpenSeadragon(options) {
1560
1582
  return result;
1561
1583
  },
1562
1584
 
1585
+
1563
1586
  /**
1564
1587
  * Determines the position of the upper-left corner of the element adjusted for current page and/or element scroll.
1565
1588
  * @function
@@ -1598,6 +1621,7 @@ function OpenSeadragon(options) {
1598
1621
  );
1599
1622
  },
1600
1623
 
1624
+
1601
1625
  /**
1602
1626
  * Determines the height and width of the given element.
1603
1627
  * @function
@@ -1613,6 +1637,7 @@ function OpenSeadragon(options) {
1613
1637
  );
1614
1638
  },
1615
1639
 
1640
+
1616
1641
  /**
1617
1642
  * Returns the CSSStyle object for the given element.
1618
1643
  * @function
@@ -1690,6 +1715,7 @@ function OpenSeadragon(options) {
1690
1715
  return result;
1691
1716
  },
1692
1717
 
1718
+
1693
1719
  /**
1694
1720
  * Determines if a point is within the bounding rectangle of the given element (hit-test).
1695
1721
  * @function
@@ -1705,6 +1731,7 @@ function OpenSeadragon(options) {
1705
1731
  offset.y + size.y && point.y >= offset.y;
1706
1732
  },
1707
1733
 
1734
+
1708
1735
  /**
1709
1736
  * Gets the position of the mouse on the screen for a given event.
1710
1737
  * @function
@@ -1746,6 +1773,7 @@ function OpenSeadragon(options) {
1746
1773
  return $.getMousePosition(event);
1747
1774
  },
1748
1775
 
1776
+
1749
1777
  /**
1750
1778
  * Determines the page's current scroll position.
1751
1779
  * @function
@@ -1872,6 +1900,7 @@ function OpenSeadragon(options) {
1872
1900
  return $.getWindowSize();
1873
1901
  },
1874
1902
 
1903
+
1875
1904
  /**
1876
1905
  * Wraps the given element in a nest of divs so that the element can
1877
1906
  * be easily centered using CSS tables
@@ -1918,6 +1947,7 @@ function OpenSeadragon(options) {
1918
1947
  return wrappers[0];
1919
1948
  },
1920
1949
 
1950
+
1921
1951
  /**
1922
1952
  * Creates an easily positionable element of the given type that therefor
1923
1953
  * serves as an excellent container element.
@@ -1938,6 +1968,7 @@ function OpenSeadragon(options) {
1938
1968
  return element;
1939
1969
  },
1940
1970
 
1971
+
1941
1972
  /**
1942
1973
  * Returns the current milliseconds, using Date.now() if available
1943
1974
  * @function
@@ -1954,6 +1985,7 @@ function OpenSeadragon(options) {
1954
1985
  return $.now();
1955
1986
  },
1956
1987
 
1988
+
1957
1989
  /**
1958
1990
  * Ensures an image is loaded correctly to support alpha transparency.
1959
1991
  * @function
@@ -1968,6 +2000,7 @@ function OpenSeadragon(options) {
1968
2000
  return img;
1969
2001
  },
1970
2002
 
2003
+
1971
2004
  /**
1972
2005
  * Sets the opacity of the specified element.
1973
2006
  * @function
@@ -1999,6 +2032,7 @@ function OpenSeadragon(options) {
1999
2032
  }
2000
2033
  },
2001
2034
 
2035
+
2002
2036
  /**
2003
2037
  * Sets the specified element's touch-action style attribute to 'none'.
2004
2038
  * @function
@@ -2013,6 +2047,7 @@ function OpenSeadragon(options) {
2013
2047
  }
2014
2048
  },
2015
2049
 
2050
+
2016
2051
  /**
2017
2052
  * Sets the specified element's pointer-events style attribute to the passed value.
2018
2053
  * @function
@@ -2027,6 +2062,7 @@ function OpenSeadragon(options) {
2027
2062
  }
2028
2063
  },
2029
2064
 
2065
+
2030
2066
  /**
2031
2067
  * Sets the specified element's pointer-events style attribute to 'none'.
2032
2068
  * @function
@@ -2036,6 +2072,7 @@ function OpenSeadragon(options) {
2036
2072
  $.setElementPointerEvents(element, 'none');
2037
2073
  },
2038
2074
 
2075
+
2039
2076
  /**
2040
2077
  * Add the specified CSS class to the element if not present.
2041
2078
  * @function
@@ -2180,6 +2217,7 @@ function OpenSeadragon(options) {
2180
2217
  }
2181
2218
  }()),
2182
2219
 
2220
+
2183
2221
  /**
2184
2222
  * Remove a given event listener for the given element, event type and
2185
2223
  * handler.
@@ -2207,6 +2245,7 @@ function OpenSeadragon(options) {
2207
2245
  }
2208
2246
  }()),
2209
2247
 
2248
+
2210
2249
  /**
2211
2250
  * Cancels the default browser behavior had the event propagated all
2212
2251
  * the way up the DOM to the window object.
@@ -2217,6 +2256,7 @@ function OpenSeadragon(options) {
2217
2256
  event.preventDefault();
2218
2257
  },
2219
2258
 
2259
+
2220
2260
  /**
2221
2261
  * Returns true if {@link OpenSeadragon.cancelEvent|cancelEvent} has been called on
2222
2262
  * the event, otherwise returns false.
@@ -2227,6 +2267,7 @@ function OpenSeadragon(options) {
2227
2267
  return event.defaultPrevented;
2228
2268
  },
2229
2269
 
2270
+
2230
2271
  /**
2231
2272
  * Stops the propagation of the event through the DOM in the capturing and bubbling phases.
2232
2273
  * @function
@@ -2236,6 +2277,7 @@ function OpenSeadragon(options) {
2236
2277
  event.stopPropagation();
2237
2278
  },
2238
2279
 
2280
+
2239
2281
  /**
2240
2282
  * Similar to OpenSeadragon.delegate, but it does not immediately call
2241
2283
  * the method on the object, returning a function which can be called
@@ -2271,6 +2313,7 @@ function OpenSeadragon(options) {
2271
2313
  };
2272
2314
  },
2273
2315
 
2316
+
2274
2317
  /**
2275
2318
  * Retrieves the value of a url parameter from the window.location string.
2276
2319
  * @function
@@ -2521,6 +2564,7 @@ function OpenSeadragon(options) {
2521
2564
 
2522
2565
  },
2523
2566
 
2567
+
2524
2568
  /**
2525
2569
  * Fully deprecated. Will throw an error.
2526
2570
  * @function
@@ -2617,6 +2661,7 @@ function OpenSeadragon(options) {
2617
2661
 
2618
2662
  });
2619
2663
 
2664
+
2620
2665
  //TODO: $.console is often used inside a try/catch block which generally
2621
2666
  // prevents allowings errors to occur with detection until a debugger
2622
2667
  // is attached. Although I've been guilty of the same anti-pattern
@@ -2641,6 +2686,7 @@ function OpenSeadragon(options) {
2641
2686
  assert: nullfunction,
2642
2687
  };
2643
2688
 
2689
+
2644
2690
  /**
2645
2691
  * The current browser vendor, version, and related information regarding detected features.
2646
2692
  * @member {Object} Browser
@@ -2657,6 +2703,7 @@ function OpenSeadragon(options) {
2657
2703
  alpha: true,
2658
2704
  };
2659
2705
 
2706
+
2660
2707
  var FILEFORMATS = {
2661
2708
  bmp: false,
2662
2709
  jpeg: true,
@@ -2770,6 +2817,7 @@ function OpenSeadragon(options) {
2770
2817
  }
2771
2818
  })();
2772
2819
 
2820
+
2773
2821
  // Adding support for HTML5's requestAnimationFrame as suggested by acdha.
2774
2822
  // Implementation taken from matt synder's post here:
2775
2823
  // http://mattsnider.com/cross-browser-and-legacy-supported-requestframeanimation/
@@ -2874,6 +2922,7 @@ function OpenSeadragon(options) {
2874
2922
 
2875
2923
  }(OpenSeadragon));
2876
2924
 
2925
+
2877
2926
  // Universal Module Definition, supports CommonJS, AMD and simple script tag
2878
2927
  (function(root, factory) {
2879
2928
  if (typeof define === 'function' && define.amd) {
@@ -3088,6 +3137,7 @@ function OpenSeadragon(options) {
3088
3137
  * @param {Object} event - See individual events for event-specific properties.
3089
3138
  */
3090
3139
 
3140
+
3091
3141
  /**
3092
3142
  * @class EventSource
3093
3143
  * @classdesc For use by classes which want to support custom, non-browser events.
@@ -3103,7 +3153,7 @@ function OpenSeadragon(options) {
3103
3153
 
3104
3154
  /**
3105
3155
  * Add an event handler to be triggered only once (or a given number of times)
3106
- * for a given event.
3156
+ * for a given event. It is not removable with removeHandler().
3107
3157
  * @function
3108
3158
  * @param {String} eventName - Name of event to register.
3109
3159
  * @param {OpenSeadragon.EventHandler} handler - Function to call when event
@@ -3112,8 +3162,9 @@ function OpenSeadragon(options) {
3112
3162
  * to the handler.
3113
3163
  * @param {Number} [times=1] - The number of times to handle the event
3114
3164
  * before removing it.
3165
+ * @param {Number} [priority=0] - Handler priority. By default, all priorities are 0. Higher number = priority.
3115
3166
  */
3116
- addOnceHandler: function(eventName, handler, userData, times) {
3167
+ addOnceHandler: function(eventName, handler, userData, times, priority) {
3117
3168
  var self = this;
3118
3169
  times = times || 1;
3119
3170
  var count = 0;
@@ -3122,9 +3173,9 @@ function OpenSeadragon(options) {
3122
3173
  if (count === times) {
3123
3174
  self.removeHandler(eventName, onceHandler);
3124
3175
  }
3125
- handler(event);
3176
+ return handler(event);
3126
3177
  };
3127
- this.addHandler(eventName, onceHandler, userData);
3178
+ this.addHandler(eventName, onceHandler, userData, priority);
3128
3179
  },
3129
3180
 
3130
3181
  /**
@@ -3133,14 +3184,27 @@ function OpenSeadragon(options) {
3133
3184
  * @param {String} eventName - Name of event to register.
3134
3185
  * @param {OpenSeadragon.EventHandler} handler - Function to call when event is triggered.
3135
3186
  * @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler.
3187
+ * @param {Number} [priority=0] - Handler priority. By default, all priorities are 0. Higher number = priority.
3136
3188
  */
3137
- addHandler: function(eventName, handler, userData) {
3189
+ addHandler: function(eventName, handler, userData, priority) {
3138
3190
  var events = this.events[eventName];
3139
3191
  if (!events) {
3140
3192
  this.events[eventName] = events = [];
3141
3193
  }
3142
3194
  if (handler && $.isFunction(handler)) {
3143
- events[events.length] = {handler: handler, userData: userData || null};
3195
+ var index = events.length,
3196
+ event = {
3197
+ handler: handler,
3198
+ userData: userData || null,
3199
+ priority: priority || 0,
3200
+ };
3201
+ events[index] = event;
3202
+ while (index > 0 && events[index - 1].priority <
3203
+ events[index].priority) {
3204
+ events[index] = events[index - 1];
3205
+ events[index - 1] = event;
3206
+ index--;
3207
+ }
3144
3208
  }
3145
3209
  },
3146
3210
 
@@ -3231,15 +3295,12 @@ function OpenSeadragon(options) {
3231
3295
  raiseEvent: function(eventName, eventArgs) {
3232
3296
  //uncomment if you want to get a log of all events
3233
3297
  //$.console.log( eventName );
3234
- var handler = this.getHandler(eventName);
3235
3298
 
3299
+ var handler = this.getHandler(eventName);
3236
3300
  if (handler) {
3237
- if (!eventArgs) {
3238
- eventArgs = {};
3239
- }
3240
-
3241
- handler(this, eventArgs);
3301
+ return handler(this, eventArgs || {});
3242
3302
  }
3303
+ return undefined;
3243
3304
  },
3244
3305
  };
3245
3306
 
@@ -3287,6 +3348,7 @@ function OpenSeadragon(options) {
3287
3348
  // dictionary from hash to private properties
3288
3349
  var THIS = {};
3289
3350
 
3351
+
3290
3352
  /**
3291
3353
  * @class MouseTracker
3292
3354
  * @classdesc Provides simplified handling of common pointer device (mouse, touch, pen, etc.) gestures
@@ -4458,6 +4520,7 @@ function OpenSeadragon(options) {
4458
4520
  };
4459
4521
  })();
4460
4522
 
4523
+
4461
4524
  ///////////////////////////////////////////////////////////////////////////////
4462
4525
  // Pointer event model and feature detection
4463
4526
  ///////////////////////////////////////////////////////////////////////////////
@@ -4539,6 +4602,7 @@ function OpenSeadragon(options) {
4539
4602
  }
4540
4603
  }
4541
4604
 
4605
+
4542
4606
  ///////////////////////////////////////////////////////////////////////////////
4543
4607
  // Classes and typedefs
4544
4608
  ///////////////////////////////////////////////////////////////////////////////
@@ -4586,6 +4650,7 @@ function OpenSeadragon(options) {
4586
4650
  * Arbitrary user-defined object.
4587
4651
  */
4588
4652
 
4653
+
4589
4654
  /**
4590
4655
  * Represents a point of contact on the screen made by a mouse cursor, pen, touch, or other pointer device.
4591
4656
  *
@@ -4622,6 +4687,7 @@ function OpenSeadragon(options) {
4622
4687
  * The current pointer contact time, in milliseconds.
4623
4688
  */
4624
4689
 
4690
+
4625
4691
  /**
4626
4692
  * @class GesturePointList
4627
4693
  * @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type.
@@ -4776,6 +4842,7 @@ function OpenSeadragon(options) {
4776
4842
  },
4777
4843
  };
4778
4844
 
4845
+
4779
4846
  ///////////////////////////////////////////////////////////////////////////////
4780
4847
  // Utility functions
4781
4848
  ///////////////////////////////////////////////////////////////////////////////
@@ -4965,6 +5032,7 @@ function OpenSeadragon(options) {
4965
5032
  updatePointerCaptured(tracker, gPoint, true);
4966
5033
  }
4967
5034
 
5035
+
4968
5036
  /**
4969
5037
  * Stop capturing pointer events to the tracked element.
4970
5038
  * @private
@@ -5026,6 +5094,7 @@ function OpenSeadragon(options) {
5026
5094
  updatePointerCaptured(tracker, gPoint, false);
5027
5095
  }
5028
5096
 
5097
+
5029
5098
  /**
5030
5099
  * Note: Called for both pointer events and legacy mouse events
5031
5100
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5038,6 +5107,7 @@ function OpenSeadragon(options) {
5038
5107
  $.MouseTracker.mousePointerId;
5039
5108
  }
5040
5109
 
5110
+
5041
5111
  /**
5042
5112
  * Gets a W3C Pointer Events model compatible pointer type string from a DOM pointer event.
5043
5113
  * IE10 used a long integer value, but the W3C specification (and IE11+) use a string "mouse", "touch", "pen", etc.
@@ -5059,6 +5129,7 @@ function OpenSeadragon(options) {
5059
5129
  }
5060
5130
  }
5061
5131
 
5132
+
5062
5133
  /**
5063
5134
  * Note: Called for both pointer events and legacy mouse events
5064
5135
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5069,6 +5140,7 @@ function OpenSeadragon(options) {
5069
5140
  return ($.MouseTracker.havePointerEvents) ? event.isPrimary : true;
5070
5141
  }
5071
5142
 
5143
+
5072
5144
  /**
5073
5145
  * @private
5074
5146
  * @inner
@@ -5102,6 +5174,7 @@ function OpenSeadragon(options) {
5102
5174
  return new $.Point((point1.x + point2.x) / 2, (point1.y + point2.y) / 2);
5103
5175
  }
5104
5176
 
5177
+
5105
5178
  ///////////////////////////////////////////////////////////////////////////////
5106
5179
  // Device-specific DOM event handlers
5107
5180
  ///////////////////////////////////////////////////////////////////////////////
@@ -5129,6 +5202,7 @@ function OpenSeadragon(options) {
5129
5202
  }
5130
5203
  }
5131
5204
 
5205
+
5132
5206
  /**
5133
5207
  * @private
5134
5208
  * @inner
@@ -5152,6 +5226,7 @@ function OpenSeadragon(options) {
5152
5226
  }
5153
5227
  }
5154
5228
 
5229
+
5155
5230
  /**
5156
5231
  * @private
5157
5232
  * @inner
@@ -5194,6 +5269,7 @@ function OpenSeadragon(options) {
5194
5269
  }
5195
5270
  }
5196
5271
 
5272
+
5197
5273
  /**
5198
5274
  * @private
5199
5275
  * @inner
@@ -5237,6 +5313,7 @@ function OpenSeadragon(options) {
5237
5313
  }
5238
5314
  }
5239
5315
 
5316
+
5240
5317
  /**
5241
5318
  * @private
5242
5319
  * @inner
@@ -5280,6 +5357,7 @@ function OpenSeadragon(options) {
5280
5357
  }
5281
5358
  }
5282
5359
 
5360
+
5283
5361
  /**
5284
5362
  * @private
5285
5363
  * @inner
@@ -5309,6 +5387,7 @@ function OpenSeadragon(options) {
5309
5387
  }
5310
5388
  }
5311
5389
 
5390
+
5312
5391
  /**
5313
5392
  * @private
5314
5393
  * @inner
@@ -5338,6 +5417,7 @@ function OpenSeadragon(options) {
5338
5417
  }
5339
5418
  }
5340
5419
 
5420
+
5341
5421
  /**
5342
5422
  * @private
5343
5423
  * @inner
@@ -5379,6 +5459,7 @@ function OpenSeadragon(options) {
5379
5459
  }
5380
5460
  }
5381
5461
 
5462
+
5382
5463
  /**
5383
5464
  * Handler for 'wheel' events
5384
5465
  *
@@ -5389,6 +5470,7 @@ function OpenSeadragon(options) {
5389
5470
  handleWheelEvent(tracker, event, event);
5390
5471
  }
5391
5472
 
5473
+
5392
5474
  /**
5393
5475
  * Handler for 'mousewheel', 'DOMMouseScroll', and 'MozMousePixelScroll' events
5394
5476
  *
@@ -5421,6 +5503,7 @@ function OpenSeadragon(options) {
5421
5503
  handleWheelEvent(tracker, simulatedEvent, event);
5422
5504
  }
5423
5505
 
5506
+
5424
5507
  /**
5425
5508
  * Handles 'wheel' events.
5426
5509
  * The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()).
@@ -5463,6 +5546,7 @@ function OpenSeadragon(options) {
5463
5546
  userData: tracker.userData,
5464
5547
  };
5465
5548
 
5549
+
5466
5550
  tracker.scrollHandler(eventArgs);
5467
5551
  }
5468
5552
 
@@ -5475,6 +5559,7 @@ function OpenSeadragon(options) {
5475
5559
  }
5476
5560
  }
5477
5561
 
5562
+
5478
5563
  /**
5479
5564
  * TODO Never actually seen this event fired, and documentation is tough to find
5480
5565
  * @private
@@ -5505,6 +5590,7 @@ function OpenSeadragon(options) {
5505
5590
  }
5506
5591
  }
5507
5592
 
5593
+
5508
5594
  /**
5509
5595
  * @private
5510
5596
  * @inner
@@ -5559,6 +5645,7 @@ function OpenSeadragon(options) {
5559
5645
  }
5560
5646
  }
5561
5647
 
5648
+
5562
5649
  /**
5563
5650
  * @private
5564
5651
  * @inner
@@ -5605,6 +5692,7 @@ function OpenSeadragon(options) {
5605
5692
  }
5606
5693
  }
5607
5694
 
5695
+
5608
5696
  /**
5609
5697
  * @private
5610
5698
  * @inner
@@ -5644,6 +5732,7 @@ function OpenSeadragon(options) {
5644
5732
  }
5645
5733
  }
5646
5734
 
5735
+
5647
5736
  /**
5648
5737
  * @private
5649
5738
  * @inner
@@ -5678,6 +5767,7 @@ function OpenSeadragon(options) {
5678
5767
  }
5679
5768
  }
5680
5769
 
5770
+
5681
5771
  /**
5682
5772
  * @private
5683
5773
  * @inner
@@ -5689,6 +5779,7 @@ function OpenSeadragon(options) {
5689
5779
  return false;
5690
5780
  }
5691
5781
 
5782
+
5692
5783
  /**
5693
5784
  * @private
5694
5785
  * @inner
@@ -5700,6 +5791,7 @@ function OpenSeadragon(options) {
5700
5791
  return false;
5701
5792
  }
5702
5793
 
5794
+
5703
5795
  /**
5704
5796
  * @private
5705
5797
  * @inner
@@ -5728,6 +5820,7 @@ function OpenSeadragon(options) {
5728
5820
  }
5729
5821
  }
5730
5822
 
5823
+
5731
5824
  /**
5732
5825
  * @private
5733
5826
  * @inner
@@ -5756,6 +5849,7 @@ function OpenSeadragon(options) {
5756
5849
  }
5757
5850
  }
5758
5851
 
5852
+
5759
5853
  /**
5760
5854
  * Note: Called for both pointer events and legacy mouse events
5761
5855
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5788,6 +5882,7 @@ function OpenSeadragon(options) {
5788
5882
  updatePointerEnter(tracker, eventInfo, gPoint);
5789
5883
  }
5790
5884
 
5885
+
5791
5886
  /**
5792
5887
  * Note: Called for both pointer events and legacy mouse events
5793
5888
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5820,6 +5915,7 @@ function OpenSeadragon(options) {
5820
5915
  updatePointerLeave(tracker, eventInfo, gPoint);
5821
5916
  }
5822
5917
 
5918
+
5823
5919
  /**
5824
5920
  * Note: Called for both pointer events and legacy mouse events
5825
5921
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5856,6 +5952,7 @@ function OpenSeadragon(options) {
5856
5952
  }
5857
5953
  }
5858
5954
 
5955
+
5859
5956
  /**
5860
5957
  * Note: Called for both pointer events and legacy mouse events
5861
5958
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5892,6 +5989,7 @@ function OpenSeadragon(options) {
5892
5989
  }
5893
5990
  }
5894
5991
 
5992
+
5895
5993
  /**
5896
5994
  * Note: Called for both pointer events and legacy mouse events
5897
5995
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5946,6 +6044,7 @@ function OpenSeadragon(options) {
5946
6044
  }
5947
6045
  }
5948
6046
 
6047
+
5949
6048
  /**
5950
6049
  * Note: Called for both pointer events and legacy mouse events
5951
6050
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5957,6 +6056,7 @@ function OpenSeadragon(options) {
5957
6056
  handlePointerUp(tracker, event);
5958
6057
  }
5959
6058
 
6059
+
5960
6060
  /**
5961
6061
  * Note: Called for both pointer events and legacy mouse events
5962
6062
  * ($.MouseTracker.havePointerEvents determines which)
@@ -5975,6 +6075,7 @@ function OpenSeadragon(options) {
5975
6075
  $.stopEvent(event);
5976
6076
  }
5977
6077
 
6078
+
5978
6079
  /**
5979
6080
  * Note: Called for both pointer events and legacy mouse events
5980
6081
  * ($.MouseTracker.havePointerEvents determines which)
@@ -6024,6 +6125,7 @@ function OpenSeadragon(options) {
6024
6125
  }
6025
6126
  }
6026
6127
 
6128
+
6027
6129
  /**
6028
6130
  * Note: Called for both pointer events and legacy mouse events
6029
6131
  * ($.MouseTracker.havePointerEvents determines which)
@@ -6035,6 +6137,7 @@ function OpenSeadragon(options) {
6035
6137
  handlePointerMove(tracker, event);
6036
6138
  }
6037
6139
 
6140
+
6038
6141
  /**
6039
6142
  * Note: Called for both pointer events and legacy mouse events
6040
6143
  * ($.MouseTracker.havePointerEvents determines which)
@@ -6053,6 +6156,7 @@ function OpenSeadragon(options) {
6053
6156
  $.stopEvent(event);
6054
6157
  }
6055
6158
 
6159
+
6056
6160
  /**
6057
6161
  * Note: Called for both pointer events and legacy mouse events
6058
6162
  * ($.MouseTracker.havePointerEvents determines which)
@@ -6089,6 +6193,7 @@ function OpenSeadragon(options) {
6089
6193
  }
6090
6194
  }
6091
6195
 
6196
+
6092
6197
  /**
6093
6198
  * @private
6094
6199
  * @inner
@@ -6117,6 +6222,7 @@ function OpenSeadragon(options) {
6117
6222
  }
6118
6223
  }
6119
6224
 
6225
+
6120
6226
  ///////////////////////////////////////////////////////////////////////////////
6121
6227
  // Device-agnostic DOM event handlers
6122
6228
  ///////////////////////////////////////////////////////////////////////////////
@@ -6143,6 +6249,7 @@ function OpenSeadragon(options) {
6143
6249
  return pointsList.add(gPoint);
6144
6250
  }
6145
6251
 
6252
+
6146
6253
  /**
6147
6254
  * @function
6148
6255
  * @private
@@ -6180,6 +6287,7 @@ function OpenSeadragon(options) {
6180
6287
  return listLength;
6181
6288
  }
6182
6289
 
6290
+
6183
6291
  /**
6184
6292
  * @function
6185
6293
  * @private
@@ -6264,6 +6372,7 @@ function OpenSeadragon(options) {
6264
6372
  }
6265
6373
  }
6266
6374
 
6375
+
6267
6376
  /**
6268
6377
  * Sets up for and calls preProcessEventHandler. Call with the following parameters -
6269
6378
  * this function will fill in the rest of the preProcessEventHandler event object
@@ -6297,6 +6406,7 @@ function OpenSeadragon(options) {
6297
6406
  }
6298
6407
  }
6299
6408
 
6409
+
6300
6410
  /**
6301
6411
  * Sets or resets the captured property on the tracked pointer matching the passed gPoint's id/type
6302
6412
  *
@@ -6332,6 +6442,7 @@ function OpenSeadragon(options) {
6332
6442
  }
6333
6443
  }
6334
6444
 
6445
+
6335
6446
  /**
6336
6447
  * @function
6337
6448
  * @private
@@ -6386,6 +6497,7 @@ function OpenSeadragon(options) {
6386
6497
  }
6387
6498
  }
6388
6499
 
6500
+
6389
6501
  /**
6390
6502
  * @function
6391
6503
  * @private
@@ -6450,6 +6562,7 @@ function OpenSeadragon(options) {
6450
6562
  }
6451
6563
  }
6452
6564
 
6565
+
6453
6566
  /**
6454
6567
  * @function
6455
6568
  * @private
@@ -6542,6 +6655,7 @@ function OpenSeadragon(options) {
6542
6655
  }
6543
6656
  }
6544
6657
 
6658
+
6545
6659
  /**
6546
6660
  * @function
6547
6661
  * @private
@@ -6687,6 +6801,7 @@ function OpenSeadragon(options) {
6687
6801
  }
6688
6802
  }
6689
6803
 
6804
+
6690
6805
  /**
6691
6806
  * @function
6692
6807
  * @private
@@ -6947,6 +7062,7 @@ function OpenSeadragon(options) {
6947
7062
  }
6948
7063
  }
6949
7064
 
7065
+
6950
7066
  /**
6951
7067
  * Call when pointer(s) change coordinates, button state, pressure, tilt, or contact geometry (e.g. width and height)
6952
7068
  *
@@ -7106,6 +7222,7 @@ function OpenSeadragon(options) {
7106
7222
  }
7107
7223
  }
7108
7224
 
7225
+
7109
7226
  /**
7110
7227
  * @function
7111
7228
  * @private
@@ -7128,6 +7245,7 @@ function OpenSeadragon(options) {
7128
7245
  }
7129
7246
  }
7130
7247
 
7248
+
7131
7249
  /**
7132
7250
  * @private
7133
7251
  * @inner
@@ -7514,6 +7632,7 @@ function OpenSeadragon(options) {
7514
7632
  element.style.display = 'inline-block';
7515
7633
  },
7516
7634
 
7635
+
7517
7636
  /**
7518
7637
  * @function
7519
7638
  * @returns {OpenSeadragon.ControlDock} Chainable.
@@ -7542,6 +7661,7 @@ function OpenSeadragon(options) {
7542
7661
  return this;
7543
7662
  },
7544
7663
 
7664
+
7545
7665
  /**
7546
7666
  * @function
7547
7667
  * @returns {Boolean}
@@ -7558,6 +7678,7 @@ function OpenSeadragon(options) {
7558
7678
  return false;
7559
7679
  },
7560
7680
 
7681
+
7561
7682
  /**
7562
7683
  * @function
7563
7684
  * @returns {OpenSeadragon.ControlDock} Chainable.
@@ -7574,6 +7695,7 @@ function OpenSeadragon(options) {
7574
7695
 
7575
7696
  };
7576
7697
 
7698
+
7577
7699
  ///////////////////////////////////////////////////////////////////////////////
7578
7700
  // Utility methods
7579
7701
  ///////////////////////////////////////////////////////////////////////////////
@@ -7801,6 +7923,7 @@ function OpenSeadragon(options) {
7801
7923
  _this = this,
7802
7924
  i;
7803
7925
 
7926
+
7804
7927
  //backward compatibility for positional args while preferring more
7805
7928
  //idiomatic javascript options object as the only argument
7806
7929
  if (!$.isPlainObject(options)) {
@@ -8044,6 +8167,8 @@ function OpenSeadragon(options) {
8044
8167
  nonPrimaryReleaseHandler: $.delegate(this, onCanvasNonPrimaryRelease),
8045
8168
  scrollHandler: $.delegate(this, onCanvasScroll),
8046
8169
  pinchHandler: $.delegate(this, onCanvasPinch),
8170
+ focusHandler: $.delegate(this, onCanvasFocus),
8171
+ blurHandler: $.delegate(this, onCanvasBlur),
8047
8172
  });
8048
8173
 
8049
8174
  this.outerTracker = new $.MouseTracker({
@@ -8145,6 +8270,8 @@ function OpenSeadragon(options) {
8145
8270
  this.imageLoader = new $.ImageLoader({
8146
8271
  jobLimit: this.imageLoaderLimit,
8147
8272
  timeout: options.timeout,
8273
+ tileRetryMax: this.tileRetryMax,
8274
+ tileRetryDelay: this.tileRetryDelay,
8148
8275
  });
8149
8276
 
8150
8277
  // Create the tile cache
@@ -8243,6 +8370,7 @@ function OpenSeadragon(options) {
8243
8370
  $.extend($.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, /** @lends OpenSeadragon.Viewer.prototype */
8244
8371
  {
8245
8372
 
8373
+
8246
8374
  /**
8247
8375
  * @function
8248
8376
  * @returns {Boolean}
@@ -8458,6 +8586,7 @@ function OpenSeadragon(options) {
8458
8586
  return this;
8459
8587
  },
8460
8588
 
8589
+
8461
8590
  /**
8462
8591
  * @function
8463
8592
  * @returns {OpenSeadragon.Viewer} Chainable.
@@ -8499,6 +8628,7 @@ function OpenSeadragon(options) {
8499
8628
  return this;
8500
8629
  },
8501
8630
 
8631
+
8502
8632
  /**
8503
8633
  * Function to destroy the viewer and clean up everything created by OpenSeadragon.
8504
8634
  *
@@ -8567,6 +8697,7 @@ function OpenSeadragon(options) {
8567
8697
  this.navigator = null;
8568
8698
  }
8569
8699
 
8700
+
8570
8701
  if (this.buttonGroup) {
8571
8702
  this.buttonGroup.destroy();
8572
8703
  } else if (this.customButtons) {
@@ -8657,6 +8788,7 @@ function OpenSeadragon(options) {
8657
8788
  return this;
8658
8789
  },
8659
8790
 
8791
+
8660
8792
  /**
8661
8793
  * @function
8662
8794
  * @returns {Boolean}
@@ -8670,6 +8802,7 @@ function OpenSeadragon(options) {
8670
8802
  return enabled;
8671
8803
  },
8672
8804
 
8805
+
8673
8806
  /**
8674
8807
  * Shows or hides the controls (e.g. the default navigation buttons).
8675
8808
  *
@@ -8702,7 +8835,7 @@ function OpenSeadragon(options) {
8702
8835
  * Turns debugging mode on or off for this viewer.
8703
8836
  *
8704
8837
  * @function
8705
- * @param {Boolean} true to turn debug on, false to turn debug off.
8838
+ * @param {Boolean} debugMode true to turn debug on, false to turn debug off.
8706
8839
  */
8707
8840
  setDebugMode: function(debugMode) {
8708
8841
 
@@ -8714,6 +8847,65 @@ function OpenSeadragon(options) {
8714
8847
  this.forceRedraw();
8715
8848
  },
8716
8849
 
8850
+ /**
8851
+ * Update headers to include when making AJAX requests.
8852
+ *
8853
+ * Unless `propagate` is set to false (which is likely only useful in rare circumstances),
8854
+ * the updated headers are propagated to all tiled images, each of which will subsequently
8855
+ * propagate the changed headers to all their tiles.
8856
+ * If applicable, the headers of the viewer's navigator and reference strip will also be updated.
8857
+ *
8858
+ * Note that the rules for merging headers still apply, i.e. headers returned by
8859
+ * {@link OpenSeadragon.TileSource#getTileAjaxHeaders} take precedence over
8860
+ * `TiledImage.ajaxHeaders`, which take precedence over the headers here in the viewer.
8861
+ *
8862
+ * @function
8863
+ * @param {Object} ajaxHeaders Updated AJAX headers.
8864
+ * @param {Boolean} [propagate=true] Whether to propagate updated headers to tiled images, etc.
8865
+ */
8866
+ setAjaxHeaders: function(ajaxHeaders, propagate) {
8867
+ if (ajaxHeaders === null) {
8868
+ ajaxHeaders = {};
8869
+ }
8870
+ if (!$.isPlainObject(ajaxHeaders)) {
8871
+ console.error(
8872
+ '[Viewer.setAjaxHeaders] Ignoring invalid headers, must be a plain object');
8873
+ return;
8874
+ }
8875
+ if (propagate === undefined) {
8876
+ propagate = true;
8877
+ }
8878
+
8879
+ this.ajaxHeaders = ajaxHeaders;
8880
+
8881
+ if (propagate) {
8882
+ for (var i = 0; i < this.world.getItemCount(); i++) {
8883
+ this.world.getItemAt(i)._updateAjaxHeaders(true);
8884
+ }
8885
+
8886
+ if (this.navigator) {
8887
+ this.navigator.setAjaxHeaders(this.ajaxHeaders, true);
8888
+ }
8889
+
8890
+ if (this.referenceStrip && this.referenceStrip.miniViewers) {
8891
+ for (var key in this.referenceStrip.miniViewers) {
8892
+ this.referenceStrip.miniViewers[key].setAjaxHeaders(
8893
+ this.ajaxHeaders, true);
8894
+ }
8895
+ }
8896
+ }
8897
+ },
8898
+
8899
+ /**
8900
+ * Adds the given button to this viewer.
8901
+ *
8902
+ * @function
8903
+ * @param {OpenSeadragon.Button} button
8904
+ */
8905
+ addButton: function(button) {
8906
+ this.buttonGroup.addButton(button);
8907
+ },
8908
+
8717
8909
  /**
8718
8910
  * @function
8719
8911
  * @returns {Boolean}
@@ -8722,6 +8914,7 @@ function OpenSeadragon(options) {
8722
8914
  return THIS[this.hash].fullPage;
8723
8915
  },
8724
8916
 
8917
+
8725
8918
  /**
8726
8919
  * Toggle full page mode.
8727
8920
  * @function
@@ -9046,6 +9239,7 @@ function OpenSeadragon(options) {
9046
9239
  return this.container.style.visibility !== 'hidden';
9047
9240
  },
9048
9241
 
9242
+
9049
9243
  //
9050
9244
  /**
9051
9245
  * @function
@@ -9129,7 +9323,6 @@ function OpenSeadragon(options) {
9129
9323
  * A set of headers to include when making tile AJAX requests.
9130
9324
  * Note that these headers will be merged over any headers specified in {@link OpenSeadragon.Options}.
9131
9325
  * Specifying a falsy value for a header will clear its existing value set at the Viewer level (if any).
9132
- * requests.
9133
9326
  * @param {Function} [options.success] A function that gets called when the image is
9134
9327
  * successfully added. It's passed the event object which contains a single property:
9135
9328
  * "item", which is the resulting instance of TiledImage.
@@ -9182,12 +9375,8 @@ function OpenSeadragon(options) {
9182
9375
  if (options.loadTilesWithAjax === undefined) {
9183
9376
  options.loadTilesWithAjax = this.loadTilesWithAjax;
9184
9377
  }
9185
- if (options.ajaxHeaders === undefined || options.ajaxHeaders === null) {
9186
- options.ajaxHeaders = this.ajaxHeaders;
9187
- } else if ($.isPlainObject(options.ajaxHeaders) &&
9188
- $.isPlainObject(this.ajaxHeaders)) {
9189
- options.ajaxHeaders = $.extend({}, this.ajaxHeaders,
9190
- options.ajaxHeaders);
9378
+ if (!$.isPlainObject(options.ajaxHeaders)) {
9379
+ options.ajaxHeaders = {};
9191
9380
  }
9192
9381
 
9193
9382
  var myQueueItem = {
@@ -9555,6 +9744,7 @@ function OpenSeadragon(options) {
9555
9744
  return this;
9556
9745
  },
9557
9746
 
9747
+
9558
9748
  /**
9559
9749
  * @function
9560
9750
  * @returns {OpenSeadragon.Viewer} Chainable.
@@ -9579,6 +9769,7 @@ function OpenSeadragon(options) {
9579
9769
  buttons = [],
9580
9770
  useGroup = true;
9581
9771
 
9772
+
9582
9773
  if (this.showNavigationControl) {
9583
9774
 
9584
9775
  if (this.zoomInButton || this.zoomOutButton ||
@@ -10205,6 +10396,7 @@ function OpenSeadragon(options) {
10205
10396
  },
10206
10397
  });
10207
10398
 
10399
+
10208
10400
  /**
10209
10401
  * _getSafeElemSize is like getElementSize(), but refuses to return 0 for x or y,
10210
10402
  * which was causing some calling operations to return NaN.
@@ -10220,6 +10412,7 @@ function OpenSeadragon(options) {
10220
10412
  );
10221
10413
  }
10222
10414
 
10415
+
10223
10416
  /**
10224
10417
  * @function
10225
10418
  * @private
@@ -10409,6 +10602,7 @@ function OpenSeadragon(options) {
10409
10602
  });
10410
10603
  }
10411
10604
 
10605
+
10412
10606
  //provides a sequence in the fade animation
10413
10607
  function scheduleControlsFade(viewer) {
10414
10608
  $.requestAnimationFrame(function() {
@@ -10416,6 +10610,7 @@ function OpenSeadragon(options) {
10416
10610
  });
10417
10611
  }
10418
10612
 
10613
+
10419
10614
  //initiates an animation to hide the controls
10420
10615
  function beginControlsAutoHide(viewer) {
10421
10616
  if (!viewer.autoHideControls) {
@@ -10431,6 +10626,7 @@ function OpenSeadragon(options) {
10431
10626
  }, viewer.controlsFadeDelay);
10432
10627
  }
10433
10628
 
10629
+
10434
10630
  //determines if fade animation is done or continues the animation
10435
10631
  function updateControlsFade(viewer) {
10436
10632
  var currentTime,
@@ -10458,6 +10654,7 @@ function OpenSeadragon(options) {
10458
10654
  }
10459
10655
  }
10460
10656
 
10657
+
10461
10658
  //stop the fade animation on the controls and show them
10462
10659
  function abortControlsAutoHide(viewer) {
10463
10660
  var i;
@@ -10467,6 +10664,7 @@ function OpenSeadragon(options) {
10467
10664
  }
10468
10665
  }
10469
10666
 
10667
+
10470
10668
  ///////////////////////////////////////////////////////////////////////////////
10471
10669
  // Default view event handlers.
10472
10670
  ///////////////////////////////////////////////////////////////////////////////
@@ -10532,7 +10730,7 @@ function OpenSeadragon(options) {
10532
10730
  if (!canvasKeyDownEventArgs.preventDefaultAction && !event.ctrl &&
10533
10731
  !event.alt && !event.meta) {
10534
10732
  switch (event.keyCode) {
10535
- case 38://up arrow
10733
+ case 38://up arrow/shift uparrow
10536
10734
  if (!canvasKeyDownEventArgs.preventVerticalPan) {
10537
10735
  if (event.shift) {
10538
10736
  this.viewport.zoomBy(1.1);
@@ -10544,7 +10742,7 @@ function OpenSeadragon(options) {
10544
10742
  }
10545
10743
  event.preventDefault = true;
10546
10744
  break;
10547
- case 40://down arrow
10745
+ case 40://down arrow/shift downarrow
10548
10746
  if (!canvasKeyDownEventArgs.preventVerticalPan) {
10549
10747
  if (event.shift) {
10550
10748
  this.viewport.zoomBy(0.9);
@@ -10572,37 +10770,12 @@ function OpenSeadragon(options) {
10572
10770
  }
10573
10771
  event.preventDefault = true;
10574
10772
  break;
10575
- default:
10576
- //console.log( 'navigator keycode %s', event.keyCode );
10577
- event.preventDefault = false;
10578
- break;
10579
- }
10580
- } else {
10581
- event.preventDefault = false;
10582
- }
10583
- }
10584
-
10585
- function onCanvasKeyPress(event) {
10586
- var canvasKeyPressEventArgs = {
10587
- originalEvent: event.originalEvent,
10588
- preventDefaultAction: false,
10589
- preventVerticalPan: event.preventVerticalPan || !this.panVertical,
10590
- preventHorizontalPan: event.preventHorizontalPan || !this.panHorizontal,
10591
- };
10592
-
10593
- // This event is documented in onCanvasKeyDown
10594
- this.raiseEvent('canvas-key', canvasKeyPressEventArgs);
10595
-
10596
- if (!canvasKeyPressEventArgs.preventDefaultAction && !event.ctrl &&
10597
- !event.alt && !event.meta) {
10598
- switch (event.keyCode) {
10599
- case 43://=|+
10600
- case 61://=|+
10773
+ case 187://=|+
10601
10774
  this.viewport.zoomBy(1.1);
10602
10775
  this.viewport.applyConstraints();
10603
10776
  event.preventDefault = true;
10604
10777
  break;
10605
- case 45://-|_
10778
+ case 189://-|_
10606
10779
  this.viewport.zoomBy(0.9);
10607
10780
  this.viewport.applyConstraints();
10608
10781
  event.preventDefault = true;
@@ -10612,9 +10785,8 @@ function OpenSeadragon(options) {
10612
10785
  this.viewport.applyConstraints();
10613
10786
  event.preventDefault = true;
10614
10787
  break;
10615
- case 119://w
10616
- case 87://W
10617
- if (!canvasKeyPressEventArgs.preventVerticalPan) {
10788
+ case 87://W/w
10789
+ if (!canvasKeyDownEventArgs.preventVerticalPan) {
10618
10790
  if (event.shift) {
10619
10791
  this.viewport.zoomBy(1.1);
10620
10792
  } else {
@@ -10625,9 +10797,8 @@ function OpenSeadragon(options) {
10625
10797
  }
10626
10798
  event.preventDefault = true;
10627
10799
  break;
10628
- case 115://s
10629
- case 83://S
10630
- if (!canvasKeyPressEventArgs.preventVerticalPan) {
10800
+ case 83://S/s
10801
+ if (!canvasKeyDownEventArgs.preventVerticalPan) {
10631
10802
  if (event.shift) {
10632
10803
  this.viewport.zoomBy(0.9);
10633
10804
  } else {
@@ -10638,56 +10809,55 @@ function OpenSeadragon(options) {
10638
10809
  }
10639
10810
  event.preventDefault = true;
10640
10811
  break;
10641
- case 97://a
10642
- if (!canvasKeyPressEventArgs.preventHorizontalPan) {
10812
+ case 65://a/A
10813
+ if (!canvasKeyDownEventArgs.preventHorizontalPan) {
10643
10814
  this.viewport.panBy(
10644
10815
  this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));
10645
10816
  this.viewport.applyConstraints();
10646
10817
  }
10647
10818
  event.preventDefault = true;
10648
10819
  break;
10649
- case 100://d
10650
- if (!canvasKeyPressEventArgs.preventHorizontalPan) {
10820
+ case 68://d/D
10821
+ if (!canvasKeyDownEventArgs.preventHorizontalPan) {
10651
10822
  this.viewport.panBy(
10652
10823
  this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));
10653
10824
  this.viewport.applyConstraints();
10654
10825
  }
10655
10826
  event.preventDefault = true;
10656
10827
  break;
10657
- case 114: //r - clockwise rotation
10658
- if (this.viewport.flipped) {
10659
- this.viewport.setRotation(
10660
- this.viewport.getRotation() - this.rotationIncrement);
10661
- } else {
10662
- this.viewport.setRotation(
10663
- this.viewport.getRotation() + this.rotationIncrement);
10664
- }
10665
- this.viewport.applyConstraints();
10666
- event.preventDefault = true;
10667
- break;
10668
- case 82: //R - counterclockwise rotation
10669
- if (this.viewport.flipped) {
10670
- this.viewport.setRotation(
10671
- this.viewport.getRotation() + this.rotationIncrement);
10828
+ case 82: //r - clockwise rotation/R - counterclockwise rotation
10829
+ if (event.shift) {
10830
+ if (this.viewport.flipped) {
10831
+ this.viewport.setRotation(
10832
+ this.viewport.getRotation() + this.rotationIncrement);
10833
+ } else {
10834
+ this.viewport.setRotation(
10835
+ this.viewport.getRotation() - this.rotationIncrement);
10836
+ }
10672
10837
  } else {
10673
- this.viewport.setRotation(
10674
- this.viewport.getRotation() - this.rotationIncrement);
10838
+ if (this.viewport.flipped) {
10839
+ this.viewport.setRotation(
10840
+ this.viewport.getRotation() - this.rotationIncrement);
10841
+ } else {
10842
+ this.viewport.setRotation(
10843
+ this.viewport.getRotation() + this.rotationIncrement);
10844
+ }
10675
10845
  }
10676
10846
  this.viewport.applyConstraints();
10677
10847
  event.preventDefault = true;
10678
10848
  break;
10679
- case 102: //f
10849
+ case 70: //f/F
10680
10850
  this.viewport.toggleFlip();
10681
10851
  event.preventDefault = true;
10682
10852
  break;
10683
- case 106: //j - previous image source
10853
+ case 74: //j - previous image source
10684
10854
  this.goToPreviousPage();
10685
10855
  break;
10686
- case 107: //k - next image source
10856
+ case 75: //k - next image source
10687
10857
  this.goToNextPage();
10688
10858
  break;
10689
10859
  default:
10690
- // console.log( 'navigator keycode %s', event.keyCode );
10860
+ //console.log( 'navigator keycode %s', event.keyCode );
10691
10861
  event.preventDefault = false;
10692
10862
  break;
10693
10863
  }
@@ -10696,6 +10866,25 @@ function OpenSeadragon(options) {
10696
10866
  }
10697
10867
  }
10698
10868
 
10869
+ function onCanvasKeyPress(event) {
10870
+ var canvasKeyPressEventArgs = {
10871
+ originalEvent: event.originalEvent,
10872
+ };
10873
+
10874
+ /**
10875
+ * Raised when a keyboard key is pressed and the focus is on the {@link OpenSeadragon.Viewer#canvas} element.
10876
+ *
10877
+ * @event canvas-key-press
10878
+ * @memberof OpenSeadragon.Viewer
10879
+ * @type {object}
10880
+ * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
10881
+ * @property {Object} originalEvent - The original DOM event.
10882
+ * @property {?Object} userData - Arbitrary subscriber-defined object.
10883
+ */
10884
+
10885
+ this.raiseEvent('canvas-key-press', canvasKeyPressEventArgs);
10886
+ }
10887
+
10699
10888
  function onCanvasClick(event) {
10700
10889
  var gestureSettings;
10701
10890
 
@@ -10738,6 +10927,7 @@ function OpenSeadragon(options) {
10738
10927
 
10739
10928
  this.raiseEvent('canvas-click', canvasClickEventArgs);
10740
10929
 
10930
+
10741
10931
  if (!canvasClickEventArgs.preventDefaultAction && this.viewport &&
10742
10932
  event.quick) {
10743
10933
  gestureSettings = this.gestureSettingsByDeviceType(event.pointerType);
@@ -10944,11 +11134,13 @@ function OpenSeadragon(options) {
10944
11134
  this.viewport.applyConstraints();
10945
11135
  }
10946
11136
 
11137
+
10947
11138
  if (gestureSettings.dblClickDragToZoom && THIS[this.hash].draggingToZoom ===
10948
11139
  true) {
10949
11140
  THIS[this.hash].draggingToZoom = false;
10950
11141
  }
10951
11142
 
11143
+
10952
11144
  }
10953
11145
 
10954
11146
  function onCanvasEnter(event) {
@@ -11038,6 +11230,7 @@ function OpenSeadragon(options) {
11038
11230
  originalEvent: event.originalEvent,
11039
11231
  });
11040
11232
 
11233
+
11041
11234
  gestureSettings = this.gestureSettingsByDeviceType(event.pointerType);
11042
11235
  if (gestureSettings.dblClickDragToZoom) {
11043
11236
  var lastClickTime = THIS[this.hash].lastClickTime;
@@ -11216,12 +11409,50 @@ function OpenSeadragon(options) {
11216
11409
  var angle2 = Math.atan2(
11217
11410
  event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y,
11218
11411
  event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x);
11219
- this.viewport.setRotation(
11220
- this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI)));
11412
+ centerPt = this.viewport.pointFromPixel(event.center, true);
11413
+ this.viewport.rotateTo(this.viewport.getRotation(true) +
11414
+ ((angle1 - angle2) * (180 / Math.PI)), centerPt, true);
11221
11415
  }
11222
11416
  }
11223
11417
  }
11224
11418
 
11419
+ function onCanvasFocus(event) {
11420
+
11421
+ /**
11422
+ * Raised when the {@link OpenSeadragon.Viewer#canvas} element gets keyboard focus.
11423
+ *
11424
+ * @event canvas-focus
11425
+ * @memberof OpenSeadragon.Viewer
11426
+ * @type {object}
11427
+ * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
11428
+ * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
11429
+ * @property {Object} originalEvent - The original DOM event.
11430
+ * @property {?Object} userData - Arbitrary subscriber-defined object.
11431
+ */
11432
+ this.raiseEvent('canvas-focus', {
11433
+ tracker: event.eventSource,
11434
+ originalEvent: event.originalEvent,
11435
+ });
11436
+ }
11437
+
11438
+ function onCanvasBlur(event) {
11439
+ /**
11440
+ * Raised when the {@link OpenSeadragon.Viewer#canvas} element loses keyboard focus.
11441
+ *
11442
+ * @event canvas-blur
11443
+ * @memberof OpenSeadragon.Viewer
11444
+ * @type {object}
11445
+ * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
11446
+ * @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
11447
+ * @property {Object} originalEvent - The original DOM event.
11448
+ * @property {?Object} userData - Arbitrary subscriber-defined object.
11449
+ */
11450
+ this.raiseEvent('canvas-blur', {
11451
+ tracker: event.eventSource,
11452
+ originalEvent: event.originalEvent,
11453
+ });
11454
+ }
11455
+
11225
11456
  function onCanvasScroll(event) {
11226
11457
  var canvasScrollEventArgs,
11227
11458
  gestureSettings,
@@ -11358,6 +11589,7 @@ function OpenSeadragon(options) {
11358
11589
  });
11359
11590
  }
11360
11591
 
11592
+
11361
11593
  ///////////////////////////////////////////////////////////////////////////////
11362
11594
  // Page update routines ( aka Views - for future reference )
11363
11595
  ///////////////////////////////////////////////////////////////////////////////
@@ -11421,6 +11653,7 @@ function OpenSeadragon(options) {
11421
11653
 
11422
11654
  }
11423
11655
 
11656
+
11424
11657
  var viewportChange = viewer.viewport.update();
11425
11658
  var animated = viewer.world.update() || viewportChange;
11426
11659
 
@@ -11535,6 +11768,7 @@ function OpenSeadragon(options) {
11535
11768
  return prefix ? prefix + url : url;
11536
11769
  }
11537
11770
 
11771
+
11538
11772
  function beginZoomingIn() {
11539
11773
  THIS[this.hash].lastZoomTime = $.now();
11540
11774
  THIS[this.hash].zoomFactor = this.zoomPerSecond;
@@ -11542,6 +11776,7 @@ function OpenSeadragon(options) {
11542
11776
  scheduleZoom(this);
11543
11777
  }
11544
11778
 
11779
+
11545
11780
  function beginZoomingOut() {
11546
11781
  THIS[this.hash].lastZoomTime = $.now();
11547
11782
  THIS[this.hash].zoomFactor = 1.0 / this.zoomPerSecond;
@@ -11549,14 +11784,17 @@ function OpenSeadragon(options) {
11549
11784
  scheduleZoom(this);
11550
11785
  }
11551
11786
 
11787
+
11552
11788
  function endZooming() {
11553
11789
  THIS[this.hash].zooming = false;
11554
11790
  }
11555
11791
 
11792
+
11556
11793
  function scheduleZoom(viewer) {
11557
11794
  $.requestAnimationFrame($.delegate(viewer, doZoom));
11558
11795
  }
11559
11796
 
11797
+
11560
11798
  function doZoom() {
11561
11799
  var currentTime,
11562
11800
  deltaTime,
@@ -11574,6 +11812,7 @@ function OpenSeadragon(options) {
11574
11812
  }
11575
11813
  }
11576
11814
 
11815
+
11577
11816
  function doSingleZoomIn() {
11578
11817
  if (this.viewport) {
11579
11818
  THIS[this.hash].zooming = false;
@@ -11584,6 +11823,7 @@ function OpenSeadragon(options) {
11584
11823
  }
11585
11824
  }
11586
11825
 
11826
+
11587
11827
  function doSingleZoomOut() {
11588
11828
  if (this.viewport) {
11589
11829
  THIS[this.hash].zooming = false;
@@ -11594,6 +11834,7 @@ function OpenSeadragon(options) {
11594
11834
  }
11595
11835
  }
11596
11836
 
11837
+
11597
11838
  function lightUp() {
11598
11839
  if (this.buttonGroup) {
11599
11840
  this.buttonGroup.emulateEnter();
@@ -11601,12 +11842,14 @@ function OpenSeadragon(options) {
11601
11842
  }
11602
11843
  }
11603
11844
 
11845
+
11604
11846
  function onHome() {
11605
11847
  if (this.viewport) {
11606
11848
  this.viewport.goHome();
11607
11849
  }
11608
11850
  }
11609
11851
 
11852
+
11610
11853
  function onFullScreen() {
11611
11854
  if (this.isFullPage() && !$.isFullScreen()) {
11612
11855
  // Is fullPage but not fullScreen
@@ -11808,6 +12051,7 @@ function OpenSeadragon(options) {
11808
12051
  this.totalBorderWidths = new $.Point(this.borderWidth * 2,
11809
12052
  this.borderWidth * 2).minus(this.fudge);
11810
12053
 
12054
+
11811
12055
  if (options.controlOptions.anchor !== $.ControlAnchor.NONE) {
11812
12056
  (function(style, borderWidth) {
11813
12057
  style.margin = '0px';
@@ -11846,6 +12090,7 @@ function OpenSeadragon(options) {
11846
12090
  style.styleFloat = 'left'; //IE
11847
12091
  style.zIndex = 999999999;
11848
12092
  style.cursor = 'default';
12093
+ style.boxSizing = 'content-box';
11849
12094
  }(this.displayRegion.style, this.borderWidth));
11850
12095
  $.setElementPointerEventsNone(this.displayRegion);
11851
12096
  $.setElementTouchActionNone(this.displayRegion);
@@ -11890,10 +12135,10 @@ function OpenSeadragon(options) {
11890
12135
  this.element.getElementsByTagName('div')[0].appendChild(
11891
12136
  this.displayRegionContainer);
11892
12137
 
11893
- function rotate(degrees) {
12138
+ function rotate(degrees, immediately) {
11894
12139
  _setTransformRotate(_this.displayRegionContainer, degrees);
11895
12140
  _setTransformRotate(_this.displayRegion, -degrees);
11896
- _this.viewport.setRotation(degrees);
12141
+ _this.viewport.setRotation(degrees, immediately);
11897
12142
  }
11898
12143
 
11899
12144
  if (options.navigatorRotate) {
@@ -11901,12 +12146,13 @@ function OpenSeadragon(options) {
11901
12146
  options.viewer.viewport.getRotation() :
11902
12147
  options.viewer.degrees || 0;
11903
12148
 
11904
- rotate(degrees);
12149
+ rotate(degrees, true);
11905
12150
  options.viewer.addHandler('rotate', function(args) {
11906
- rotate(args.degrees);
12151
+ rotate(args.degrees, args.immediately);
11907
12152
  });
11908
12153
  }
11909
12154
 
12155
+
11910
12156
  // Remove the base class' (Viewer's) innerTracker and replace it with our own
11911
12157
  this.innerTracker.destroy();
11912
12158
  this.innerTracker = new $.MouseTracker({
@@ -11995,6 +12241,7 @@ function OpenSeadragon(options) {
11995
12241
  (width + 'px') :
11996
12242
  width;
11997
12243
  this._resizeWithViewer = false;
12244
+ this.updateSize();
11998
12245
  },
11999
12246
 
12000
12247
  /**
@@ -12007,6 +12254,7 @@ function OpenSeadragon(options) {
12007
12254
  (height + 'px') :
12008
12255
  height;
12009
12256
  this._resizeWithViewer = false;
12257
+ this.updateSize();
12010
12258
  },
12011
12259
 
12012
12260
  /**
@@ -12072,15 +12320,20 @@ function OpenSeadragon(options) {
12072
12320
  bottomright = this.viewport.pixelFromPointNoRotate(
12073
12321
  bounds.getBottomRight(), false).minus(this.totalBorderWidths);
12074
12322
 
12323
+ if (!this.navigatorRotate) {
12324
+ var degrees = viewport.getRotation(true);
12325
+ _setTransformRotate(this.displayRegion, -degrees);
12326
+ }
12327
+
12075
12328
  //update style for navigator-box
12076
12329
  var style = this.displayRegion.style;
12077
12330
  style.display = this.world.getItemCount() ? 'block' : 'none';
12078
12331
 
12079
- style.top = Math.round(topleft.y) + 'px';
12080
- style.left = Math.round(topleft.x) + 'px';
12332
+ style.top = topleft.y.toFixed(2) + 'px';
12333
+ style.left = topleft.x.toFixed(2) + 'px';
12081
12334
 
12082
- var width = Math.abs(topleft.x - bottomright.x);
12083
- var height = Math.abs(topleft.y - bottomright.y);
12335
+ var width = bottomright.x - topleft.x;
12336
+ var height = bottomright.y - topleft.y;
12084
12337
  // make sure width and height are non-negative so IE doesn't throw
12085
12338
  style.width = Math.round(Math.max(width, 0)) + 'px';
12086
12339
  style.height = Math.round(Math.max(height, 0)) + 'px';
@@ -12165,6 +12418,7 @@ function OpenSeadragon(options) {
12165
12418
  },
12166
12419
  });
12167
12420
 
12421
+
12168
12422
  /**
12169
12423
  * @private
12170
12424
  * @inner
@@ -12275,6 +12529,7 @@ function OpenSeadragon(options) {
12275
12529
  }
12276
12530
  }
12277
12531
 
12532
+
12278
12533
  /**
12279
12534
  * @private
12280
12535
  * @inner
@@ -12286,6 +12541,7 @@ function OpenSeadragon(options) {
12286
12541
  }
12287
12542
  }
12288
12543
 
12544
+
12289
12545
  /**
12290
12546
  * @private
12291
12547
  * @inner
@@ -12746,6 +13002,7 @@ function OpenSeadragon(options) {
12746
13002
 
12747
13003
  (function($) {
12748
13004
 
13005
+
12749
13006
  /**
12750
13007
  * @class TileSource
12751
13008
  * @classdesc The TileSource contains the most basic implementation required to create a
@@ -12947,6 +13204,7 @@ function OpenSeadragon(options) {
12947
13204
  }
12948
13205
  }
12949
13206
 
13207
+
12950
13208
  };
12951
13209
 
12952
13210
  /** @lends OpenSeadragon.TileSource.prototype */
@@ -13053,6 +13311,7 @@ function OpenSeadragon(options) {
13053
13311
  return new $.Point(rx, ry);
13054
13312
  },
13055
13313
 
13314
+
13056
13315
  /**
13057
13316
  * @function
13058
13317
  * @returns {Number} The highest level in this tile source that can be contained in a single tile.
@@ -13132,6 +13391,7 @@ function OpenSeadragon(options) {
13132
13391
  return new $.Rect(px * scale, py * scale, sx * scale, sy * scale);
13133
13392
  },
13134
13393
 
13394
+
13135
13395
  /**
13136
13396
  * Responsible for retrieving, and caching the
13137
13397
  * image metadata pertinent to this TileSources implementation.
@@ -13149,6 +13409,7 @@ function OpenSeadragon(options) {
13149
13409
  filename,
13150
13410
  lastDot;
13151
13411
 
13412
+
13152
13413
  if (url) {
13153
13414
  urlParts = url.split('/');
13154
13415
  filename = urlParts[urlParts.length - 1];
@@ -13376,6 +13637,11 @@ function OpenSeadragon(options) {
13376
13637
  * The headers returned here will override headers specified at the Viewer or TiledImage level.
13377
13638
  * Specifying a falsy value for a header will clear its existing value set at the Viewer or
13378
13639
  * TiledImage level (if any).
13640
+ *
13641
+ * Note that the headers of existing tiles don't automatically change when this function
13642
+ * returns updated headers. To do that, you need to call {@link OpenSeadragon.Viewer#setAjaxHeaders}
13643
+ * and propagate the changes.
13644
+ *
13379
13645
  * @function
13380
13646
  * @param {Number} level
13381
13647
  * @param {Number} x
@@ -13625,8 +13891,10 @@ function OpenSeadragon(options) {
13625
13891
  },
13626
13892
  };
13627
13893
 
13894
+
13628
13895
  $.extend(true, $.TileSource.prototype, $.EventSource.prototype);
13629
13896
 
13897
+
13630
13898
  /**
13631
13899
  * Decides whether to try to process the response as xml, json, or hand back
13632
13900
  * the text
@@ -13651,7 +13919,7 @@ function OpenSeadragon(options) {
13651
13919
  throw new Error($.getString('Errors.Status', status, statusText));
13652
13920
  }
13653
13921
 
13654
- if (responseText.match(/\s*<.*/)) {
13922
+ if (responseText.match(/^\s*<.*/)) {
13655
13923
  try {
13656
13924
  data = (xhr.responseXML && xhr.responseXML.documentElement) ?
13657
13925
  xhr.responseXML :
@@ -13671,6 +13939,7 @@ function OpenSeadragon(options) {
13671
13939
  return data;
13672
13940
  }
13673
13941
 
13942
+
13674
13943
  /**
13675
13944
  * Determines the TileSource Implementation by introspection of OpenSeadragon
13676
13945
  * namespace, calling each TileSource implementation of 'isType'
@@ -13698,6 +13967,7 @@ function OpenSeadragon(options) {
13698
13967
  return null;
13699
13968
  };
13700
13969
 
13970
+
13701
13971
  }(OpenSeadragon));
13702
13972
 
13703
13973
  /*
@@ -13800,6 +14070,7 @@ function OpenSeadragon(options) {
13800
14070
  $.extend($.DziTileSource.prototype,
13801
14071
  $.TileSource.prototype, /** @lends OpenSeadragon.DziTileSource.prototype */{
13802
14072
 
14073
+
13803
14074
  /**
13804
14075
  * Determine if the data and/or url imply the image service is supported by
13805
14076
  * this tile source.
@@ -13860,6 +14131,7 @@ function OpenSeadragon(options) {
13860
14131
  return options;
13861
14132
  },
13862
14133
 
14134
+
13863
14135
  /**
13864
14136
  * @function
13865
14137
  * @param {Number} level
@@ -13879,6 +14151,7 @@ function OpenSeadragon(options) {
13879
14151
  this.queryParams].join('');
13880
14152
  },
13881
14153
 
14154
+
13882
14155
  /**
13883
14156
  * @function
13884
14157
  * @param {Number} level
@@ -13931,6 +14204,7 @@ function OpenSeadragon(options) {
13931
14204
  },
13932
14205
  });
13933
14206
 
14207
+
13934
14208
  /**
13935
14209
  * @private
13936
14210
  * @inner
@@ -14094,7 +14368,7 @@ function OpenSeadragon(options) {
14094
14368
  * OpenSeadragon - IIIFTileSource
14095
14369
  *
14096
14370
  * Copyright (C) 2009 CodePlex Foundation
14097
- * Copyright (C) 2010-2022 OpenSeadragon contributors
14371
+ * Copyright (C) 2010-2023 OpenSeadragon contributors
14098
14372
  *
14099
14373
  * Redistribution and use in source and binary forms, with or without
14100
14374
  * modification, are permitted provided that the following conditions are
@@ -14236,6 +14510,19 @@ function OpenSeadragon(options) {
14236
14510
  }
14237
14511
  }
14238
14512
 
14513
+ // Create an array with our exact resolution sizes if these have been supplied
14514
+ if (this.sizes) {
14515
+ var sizeLength = this.sizes.length;
14516
+ if ((sizeLength === options.maxLevel) ||
14517
+ (sizeLength === options.maxLevel + 1)) {
14518
+ this.levelSizes = this.sizes;
14519
+ // Need to take into account that the list may or may not include the full resolution size
14520
+ if (sizeLength === options.maxLevel) {
14521
+ this.levelSizes.push({width: this.width, height: this.height});
14522
+ }
14523
+ }
14524
+ }
14525
+
14239
14526
  $.TileSource.apply(this, [options]);
14240
14527
  };
14241
14528
 
@@ -14440,9 +14727,20 @@ function OpenSeadragon(options) {
14440
14727
  }
14441
14728
  }
14442
14729
 
14443
- return $.TileSource.prototype.getNumTiles.call(this, level);
14730
+ // Use supplied list of scaled resolution sizes if these exist
14731
+ if (this.levelSizes) {
14732
+ var levelSize = this.levelSizes[level];
14733
+ var x = Math.ceil(levelSize.width / this.getTileWidth(level)),
14734
+ y = Math.ceil(levelSize.height / this.getTileHeight(level));
14735
+ return new $.Point(x, y);
14736
+ }
14737
+ // Otherwise call default TileSource->getNumTiles() function
14738
+ else {
14739
+ return $.TileSource.prototype.getNumTiles.call(this, level);
14740
+ }
14444
14741
  },
14445
14742
 
14743
+
14446
14744
  /**
14447
14745
  * @function
14448
14746
  * @param {Number} level
@@ -14454,9 +14752,39 @@ function OpenSeadragon(options) {
14454
14752
  return new $.Point(0, 0);
14455
14753
  }
14456
14754
 
14755
+ // Use supplied list of scaled resolution sizes if these exist
14756
+ if (this.levelSizes) {
14757
+
14758
+ var validPoint = point.x >= 0 && point.x <= 1 &&
14759
+ point.y >= 0 && point.y <= 1 / this.aspectRatio;
14760
+ $.console.assert(validPoint,
14761
+ '[TileSource.getTileAtPoint] must be called with a valid point.');
14762
+
14763
+ var widthScaled = this.levelSizes[level].width;
14764
+ var pixelX = point.x * widthScaled;
14765
+ var pixelY = point.y * widthScaled;
14766
+
14767
+ var x = Math.floor(pixelX / this.getTileWidth(level));
14768
+ var y = Math.floor(pixelY / this.getTileHeight(level));
14769
+
14770
+ // When point.x == 1 or point.y == 1 / this.aspectRatio we want to
14771
+ // return the last tile of the row/column
14772
+ if (point.x >= 1) {
14773
+ x = this.getNumTiles(level).x - 1;
14774
+ }
14775
+ var EPSILON = 1e-15;
14776
+ if (point.y >= 1 / this.aspectRatio - EPSILON) {
14777
+ y = this.getNumTiles(level).y - 1;
14778
+ }
14779
+
14780
+ return new $.Point(x, y);
14781
+ }
14782
+
14783
+ // Otherwise call default TileSource->getTileAtPoint() function
14457
14784
  return $.TileSource.prototype.getTileAtPoint.call(this, level, point);
14458
14785
  },
14459
14786
 
14787
+
14460
14788
  /**
14461
14789
  * Responsible for retrieving the url which will return an image for the
14462
14790
  * region specified by the given x, y, and level components.
@@ -14481,10 +14809,9 @@ function OpenSeadragon(options) {
14481
14809
  var IIIF_ROTATION = '0',
14482
14810
  //## get the scale (level as a decimal)
14483
14811
  scale = Math.pow(0.5, this.maxLevel - level),
14484
-
14485
14812
  //# image dimensions at this level
14486
- levelWidth = Math.round(this.width * scale),
14487
- levelHeight = Math.round(this.height * scale),
14813
+ levelWidth,
14814
+ levelHeight,
14488
14815
 
14489
14816
  //## iiif region
14490
14817
  tileWidth,
@@ -14502,6 +14829,17 @@ function OpenSeadragon(options) {
14502
14829
  iiifQuality,
14503
14830
  uri;
14504
14831
 
14832
+ // Use supplied list of scaled resolution sizes if these exist
14833
+ if (this.levelSizes) {
14834
+ levelWidth = this.levelSizes[level].width;
14835
+ levelHeight = this.levelSizes[level].height;
14836
+ }
14837
+ // Otherwise calculate the sizes ourselves
14838
+ else {
14839
+ levelWidth = Math.ceil(this.width * scale);
14840
+ levelHeight = Math.ceil(this.height * scale);
14841
+ }
14842
+
14505
14843
  tileWidth = this.getTileWidth(level);
14506
14844
  tileHeight = this.getTileHeight(level);
14507
14845
  iiifTileSizeWidth = Math.round(tileWidth / scale);
@@ -14534,8 +14872,8 @@ function OpenSeadragon(options) {
14534
14872
  } else {
14535
14873
  iiifRegion = [iiifTileX, iiifTileY, iiifTileW, iiifTileH].join(',');
14536
14874
  }
14537
- iiifSizeW = Math.round(iiifTileW * scale);
14538
- iiifSizeH = Math.round(iiifTileH * scale);
14875
+ iiifSizeW = Math.min(tileWidth, levelWidth - (x * tileWidth));
14876
+ iiifSizeH = Math.min(tileHeight, levelHeight - (y * tileHeight));
14539
14877
  if (this.version === 2 && iiifSizeW === this.width) {
14540
14878
  iiifSize = 'full';
14541
14879
  } else if (this.version === 3 && iiifSizeW === this.width &&
@@ -14616,6 +14954,7 @@ function OpenSeadragon(options) {
14616
14954
  });
14617
14955
  }
14618
14956
 
14957
+
14619
14958
  function configureFromXml10(xmlDoc) {
14620
14959
  //parse the xml
14621
14960
  if (!xmlDoc || !xmlDoc.documentElement) {
@@ -14664,6 +15003,7 @@ function OpenSeadragon(options) {
14664
15003
  }
14665
15004
  }
14666
15005
 
15006
+
14667
15007
  }(OpenSeadragon));
14668
15008
 
14669
15009
  /*
@@ -14707,6 +15047,7 @@ function OpenSeadragon(options) {
14707
15047
  * see <https://github.com/openseadragon/openseadragon/issues/58>.
14708
15048
  */
14709
15049
 
15050
+
14710
15051
  (function($) {
14711
15052
 
14712
15053
  /**
@@ -14770,6 +15111,7 @@ function OpenSeadragon(options) {
14770
15111
  $.extend($.OsmTileSource.prototype,
14771
15112
  $.TileSource.prototype, /** @lends OpenSeadragon.OsmTileSource.prototype */{
14772
15113
 
15114
+
14773
15115
  /**
14774
15116
  * Determine if the data and/or url imply the image service is supported by
14775
15117
  * this tile source.
@@ -14797,6 +15139,7 @@ function OpenSeadragon(options) {
14797
15139
  return data;
14798
15140
  },
14799
15141
 
15142
+
14800
15143
  /**
14801
15144
  * @function
14802
15145
  * @param {Number} level
@@ -14808,6 +15151,7 @@ function OpenSeadragon(options) {
14808
15151
  },
14809
15152
  });
14810
15153
 
15154
+
14811
15155
  }(OpenSeadragon));
14812
15156
 
14813
15157
  /*
@@ -14851,6 +15195,7 @@ function OpenSeadragon(options) {
14851
15195
  * see <https://github.com/openseadragon/openseadragon/issues/58>.
14852
15196
  */
14853
15197
 
15198
+
14854
15199
  (function($) {
14855
15200
 
14856
15201
  /**
@@ -14906,6 +15251,7 @@ function OpenSeadragon(options) {
14906
15251
  $.extend($.TmsTileSource.prototype,
14907
15252
  $.TileSource.prototype, /** @lends OpenSeadragon.TmsTileSource.prototype */{
14908
15253
 
15254
+
14909
15255
  /**
14910
15256
  * Determine if the data and/or url imply the image service is supported by
14911
15257
  * this tile source.
@@ -14930,6 +15276,7 @@ function OpenSeadragon(options) {
14930
15276
  return data;
14931
15277
  },
14932
15278
 
15279
+
14933
15280
  /**
14934
15281
  * @function
14935
15282
  * @param {Number} level
@@ -14944,6 +15291,7 @@ function OpenSeadragon(options) {
14944
15291
  },
14945
15292
  });
14946
15293
 
15294
+
14947
15295
  }(OpenSeadragon));
14948
15296
 
14949
15297
  (function($) {
@@ -15104,6 +15452,7 @@ function OpenSeadragon(options) {
15104
15452
 
15105
15453
  }(OpenSeadragon));
15106
15454
 
15455
+
15107
15456
  /*
15108
15457
  * OpenSeadragon - LegacyTileSource
15109
15458
  *
@@ -15223,6 +15572,7 @@ function OpenSeadragon(options) {
15223
15572
  );
15224
15573
  },
15225
15574
 
15575
+
15226
15576
  /**
15227
15577
  *
15228
15578
  * @function
@@ -15626,6 +15976,7 @@ function OpenSeadragon(options) {
15626
15976
  var currentWidth = this._image.naturalWidth;
15627
15977
  var currentHeight = this._image.naturalHeight;
15628
15978
 
15979
+
15629
15980
  var bigCanvas = document.createElement('canvas');
15630
15981
  var bigContext = bigCanvas.getContext('2d');
15631
15982
 
@@ -15909,6 +16260,7 @@ function OpenSeadragon(options) {
15909
16260
  this.element.appendChild(this.imgDown);
15910
16261
  }
15911
16262
 
16263
+
15912
16264
  this.addHandler('press', this.onPress);
15913
16265
  this.addHandler('release', this.onRelease);
15914
16266
  this.addHandler('click', this.onClick);
@@ -16165,6 +16517,7 @@ function OpenSeadragon(options) {
16165
16517
 
16166
16518
  });
16167
16519
 
16520
+
16168
16521
  function scheduleFade(button) {
16169
16522
  $.requestAnimationFrame(function() {
16170
16523
  updateFade(button);
@@ -16237,6 +16590,7 @@ function OpenSeadragon(options) {
16237
16590
  }
16238
16591
  }
16239
16592
 
16593
+
16240
16594
  function outTo(button, newState) {
16241
16595
 
16242
16596
  if (button.element.disabled) {
@@ -16266,6 +16620,7 @@ function OpenSeadragon(options) {
16266
16620
  }
16267
16621
  }
16268
16622
 
16623
+
16269
16624
  }(OpenSeadragon));
16270
16625
 
16271
16626
  /*
@@ -16382,6 +16737,17 @@ function OpenSeadragon(options) {
16382
16737
  /** @lends OpenSeadragon.ButtonGroup.prototype */
16383
16738
  $.ButtonGroup.prototype = {
16384
16739
 
16740
+ /**
16741
+ * Adds the given button to this button group.
16742
+ *
16743
+ * @function
16744
+ * @param {OpenSeadragon.Button} button
16745
+ */
16746
+ addButton: function(button) {
16747
+ this.buttons.push(button);
16748
+ this.element.appendChild(button.element);
16749
+ },
16750
+
16385
16751
  /**
16386
16752
  * TODO: Figure out why this is used on the public API and if a more useful
16387
16753
  * api can be created.
@@ -16413,6 +16779,7 @@ function OpenSeadragon(options) {
16413
16779
  },
16414
16780
  };
16415
16781
 
16782
+
16416
16783
  }(OpenSeadragon));
16417
16784
 
16418
16785
  /*
@@ -16977,6 +17344,7 @@ function OpenSeadragon(options) {
16977
17344
  },
16978
17345
  };
16979
17346
 
17347
+
16980
17348
  }(OpenSeadragon));
16981
17349
 
16982
17350
  /*
@@ -17272,6 +17640,7 @@ function OpenSeadragon(options) {
17272
17640
 
17273
17641
  };
17274
17642
 
17643
+
17275
17644
  /**
17276
17645
  * @private
17277
17646
  * @inner
@@ -17282,7 +17651,8 @@ function OpenSeadragon(options) {
17282
17651
  var page;
17283
17652
 
17284
17653
  if ('horizontal' === this.scroll) {
17285
- page = Math.floor(event.position.x / this.panelWidth);
17654
+ // +4px fix to solve problem with precision on thumbnail selection if there is a lot of them
17655
+ page = Math.floor(event.position.x / (this.panelWidth + 4));
17286
17656
  } else {
17287
17657
  page = Math.floor(event.position.y / this.panelHeight);
17288
17658
  }
@@ -17293,6 +17663,7 @@ function OpenSeadragon(options) {
17293
17663
  this.element.focus();
17294
17664
  }
17295
17665
 
17666
+
17296
17667
  /**
17297
17668
  * @private
17298
17669
  * @inner
@@ -17345,6 +17716,7 @@ function OpenSeadragon(options) {
17345
17716
 
17346
17717
  }
17347
17718
 
17719
+
17348
17720
  /**
17349
17721
  * @private
17350
17722
  * @inner
@@ -17396,6 +17768,7 @@ function OpenSeadragon(options) {
17396
17768
  }
17397
17769
  }
17398
17770
 
17771
+
17399
17772
  function loadPanels(strip, viewerSize, scroll) {
17400
17773
  var panelSize,
17401
17774
  activePanelsStart,
@@ -17460,6 +17833,7 @@ function OpenSeadragon(options) {
17460
17833
  }
17461
17834
  }
17462
17835
 
17836
+
17463
17837
  /**
17464
17838
  * @private
17465
17839
  * @inner
@@ -17486,6 +17860,7 @@ function OpenSeadragon(options) {
17486
17860
  }
17487
17861
  }
17488
17862
 
17863
+
17489
17864
  /**
17490
17865
  * @private
17491
17866
  * @inner
@@ -17508,6 +17883,7 @@ function OpenSeadragon(options) {
17508
17883
  }
17509
17884
  }
17510
17885
 
17886
+
17511
17887
  /**
17512
17888
  * @private
17513
17889
  * @inner
@@ -17564,6 +17940,7 @@ function OpenSeadragon(options) {
17564
17940
  }
17565
17941
  }
17566
17942
 
17943
+
17567
17944
  /**
17568
17945
  * @private
17569
17946
  * @inner
@@ -18033,17 +18410,19 @@ function OpenSeadragon(options) {
18033
18410
  * @param {Function} [options.callback] - Called once image has been downloaded.
18034
18411
  * @param {Function} [options.abort] - Called when this image job is aborted.
18035
18412
  * @param {Number} [options.timeout] - The max number of milliseconds that this image job may take to complete.
18413
+ * @param {Number} [options.tries] - Actual number of the current try.
18036
18414
  */
18037
18415
  $.ImageJob = function(options) {
18038
18416
 
18039
18417
  $.extend(true, this, {
18040
18418
  timeout: $.DEFAULT_SETTINGS.timeout,
18041
18419
  jobId: null,
18420
+ tries: 0,
18042
18421
  }, options);
18043
18422
 
18044
18423
  /**
18045
18424
  * Data object which will contain downloaded image data.
18046
- * @member {Image|*} image data object, by default an Image object (depends on TileSource)
18425
+ * @member {Image|*} data data object, by default an Image object (depends on TileSource)
18047
18426
  * @memberof OpenSeadragon.ImageJob#
18048
18427
  */
18049
18428
  this.data = null;
@@ -18070,6 +18449,8 @@ function OpenSeadragon(options) {
18070
18449
  * @method
18071
18450
  */
18072
18451
  start: function() {
18452
+ this.tries++;
18453
+
18073
18454
  var self = this;
18074
18455
  var selfAbort = this.abort;
18075
18456
 
@@ -18122,6 +18503,7 @@ function OpenSeadragon(options) {
18122
18503
  jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit,
18123
18504
  timeout: $.DEFAULT_SETTINGS.timeout,
18124
18505
  jobQueue: [],
18506
+ failedTiles: [],
18125
18507
  jobsInProgress: 0,
18126
18508
  }, options);
18127
18509
 
@@ -18204,7 +18586,8 @@ function OpenSeadragon(options) {
18204
18586
  };
18205
18587
 
18206
18588
  /**
18207
- * Cleans up ImageJob once completed.
18589
+ * Cleans up ImageJob once completed. Restarts job after tileRetryDelay seconds if failed
18590
+ * but max tileRetryMax times
18208
18591
  * @method
18209
18592
  * @private
18210
18593
  * @param loader - ImageLoader used to start job.
@@ -18212,6 +18595,10 @@ function OpenSeadragon(options) {
18212
18595
  * @param callback - Called once cleanup is finished.
18213
18596
  */
18214
18597
  function completeJob(loader, job, callback) {
18598
+ if (job.errorMsg !== '' && (job.data === null || job.data === undefined) &&
18599
+ job.tries < 1 + loader.tileRetryMax) {
18600
+ loader.failedTiles.push(job);
18601
+ }
18215
18602
  var nextJob;
18216
18603
 
18217
18604
  loader.jobsInProgress--;
@@ -18223,6 +18610,17 @@ function OpenSeadragon(options) {
18223
18610
  loader.jobsInProgress++;
18224
18611
  }
18225
18612
 
18613
+ if (loader.tileRetryMax > 0 && loader.jobQueue.length === 0) {
18614
+ if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) &&
18615
+ loader.failedTiles.length > 0) {
18616
+ nextJob = loader.failedTiles.shift();
18617
+ setTimeout(function() {
18618
+ nextJob.start();
18619
+ }, loader.tileRetryDelay);
18620
+ loader.jobsInProgress++;
18621
+ }
18622
+ }
18623
+
18226
18624
  callback(job.data, job.errorMsg, job.request);
18227
18625
  }
18228
18626
 
@@ -20120,6 +20518,7 @@ function OpenSeadragon(options) {
20120
20518
 
20121
20519
  (function($) {
20122
20520
 
20521
+
20123
20522
  /**
20124
20523
  * @class Viewport
20125
20524
  * @memberof OpenSeadragon
@@ -20815,6 +21214,8 @@ function OpenSeadragon(options) {
20815
21214
 
20816
21215
  if (constraints) {
20817
21216
  this.panTo(center, false);
21217
+
21218
+ newZoom = this._applyZoomConstraints(newZoom);
20818
21219
  this.zoomTo(newZoom, null, false);
20819
21220
 
20820
21221
  var constrainedBounds = this.getConstrainedBounds();
@@ -20901,6 +21302,7 @@ function OpenSeadragon(options) {
20901
21302
  return this.fitBounds(box, immediately);
20902
21303
  },
20903
21304
 
21305
+
20904
21306
  /**
20905
21307
  * Returns bounds taking constraints into account
20906
21308
  * Added to improve constrained panning
@@ -21186,7 +21588,10 @@ function OpenSeadragon(options) {
21186
21588
 
21187
21589
  if (this.viewer) {
21188
21590
  /**
21189
- * Raised when the viewer is resized (see {@link OpenSeadragon.Viewport#resize}).
21591
+ * Raised when a viewer resize operation is initiated (see {@link OpenSeadragon.Viewport#resize}).
21592
+ * This event happens before the viewport bounds have been updated.
21593
+ * See also {@link OpenSeadragon.Viewer#after-resize} which reflects
21594
+ * the new viewport bounds following the resize action.
21190
21595
  *
21191
21596
  * @event resize
21192
21597
  * @memberof OpenSeadragon.Viewer
@@ -21202,7 +21607,29 @@ function OpenSeadragon(options) {
21202
21607
  });
21203
21608
  }
21204
21609
 
21205
- return this.fitBounds(newBounds, true);
21610
+ var output = this.fitBounds(newBounds, true);
21611
+
21612
+ if (this.viewer) {
21613
+ /**
21614
+ * Raised after the viewer is resized (see {@link OpenSeadragon.Viewport#resize}).
21615
+ * See also {@link OpenSeadragon.Viewer#resize} event which happens
21616
+ * before the new bounds have been calculated and applied.
21617
+ *
21618
+ * @event after-resize
21619
+ * @memberof OpenSeadragon.Viewer
21620
+ * @type {object}
21621
+ * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
21622
+ * @property {OpenSeadragon.Point} newContainerSize
21623
+ * @property {Boolean} maintain
21624
+ * @property {?Object} userData - Arbitrary subscriber-defined object.
21625
+ */
21626
+ this.viewer.raiseEvent('after-resize', {
21627
+ newContainerSize: newContainerSize,
21628
+ maintain: maintain,
21629
+ });
21630
+ }
21631
+
21632
+ return output;
21206
21633
  },
21207
21634
 
21208
21635
  // private
@@ -21237,11 +21664,13 @@ function OpenSeadragon(options) {
21237
21664
  this.degreesSpring.update();
21238
21665
  }
21239
21666
 
21667
+
21240
21668
  var changed = this.centerSpringX.current.value !== this._oldCenterX ||
21241
21669
  this.centerSpringY.current.value !== this._oldCenterY ||
21242
21670
  this.zoomSpring.current.value !== this._oldZoom ||
21243
21671
  this.degreesSpring.current.value !== this._oldDegrees;
21244
21672
 
21673
+
21245
21674
  this._oldCenterX = this.centerSpringX.current.value;
21246
21675
  this._oldCenterY = this.centerSpringY.current.value;
21247
21676
  this._oldZoom = this.zoomSpring.current.value;
@@ -22031,6 +22460,9 @@ function OpenSeadragon(options) {
22031
22460
  var degrees = options.degrees || 0;
22032
22461
  delete options.degrees;
22033
22462
 
22463
+ var ajaxHeaders = options.ajaxHeaders;
22464
+ delete options.ajaxHeaders;
22465
+
22034
22466
  $.extend(true, this, {
22035
22467
 
22036
22468
  //internal state properties
@@ -22122,6 +22554,9 @@ function OpenSeadragon(options) {
22122
22554
  tiledImage: _this,
22123
22555
  }, args));
22124
22556
  };
22557
+
22558
+ this._ownAjaxHeaders = {};
22559
+ this.setAjaxHeaders(ajaxHeaders, false);
22125
22560
  };
22126
22561
 
22127
22562
  $.extend($.TiledImage.prototype,
@@ -22908,6 +23343,96 @@ function OpenSeadragon(options) {
22908
23343
  });
22909
23344
  },
22910
23345
 
23346
+ /**
23347
+ * Update headers to include when making AJAX requests.
23348
+ *
23349
+ * Unless `propagate` is set to false (which is likely only useful in rare circumstances),
23350
+ * the updated headers are propagated to all tiles and queued image loader jobs.
23351
+ *
23352
+ * Note that the rules for merging headers still apply, i.e. headers returned by
23353
+ * {@link OpenSeadragon.TileSource#getTileAjaxHeaders} take precedence over
23354
+ * the headers here in the tiled image (`TiledImage.ajaxHeaders`).
23355
+ *
23356
+ * @function
23357
+ * @param {Object} ajaxHeaders Updated AJAX headers, which will be merged over any headers specified in {@link OpenSeadragon.Options}.
23358
+ * @param {Boolean} [propagate=true] Whether to propagate updated headers to existing tiles and queued image loader jobs.
23359
+ */
23360
+ setAjaxHeaders: function(ajaxHeaders, propagate) {
23361
+ if (ajaxHeaders === null) {
23362
+ ajaxHeaders = {};
23363
+ }
23364
+ if (!$.isPlainObject(ajaxHeaders)) {
23365
+ console.error(
23366
+ '[TiledImage.setAjaxHeaders] Ignoring invalid headers, must be a plain object');
23367
+ return;
23368
+ }
23369
+
23370
+ this._ownAjaxHeaders = ajaxHeaders;
23371
+ this._updateAjaxHeaders(propagate);
23372
+ },
23373
+
23374
+ /**
23375
+ * Update headers to include when making AJAX requests.
23376
+ *
23377
+ * This function has the same effect as calling {@link OpenSeadragon.TiledImage#setAjaxHeaders},
23378
+ * except that the headers for this tiled image do not change. This is especially useful
23379
+ * for propagating updated headers from {@link OpenSeadragon.TileSource#getTileAjaxHeaders}
23380
+ * to existing tiles.
23381
+ *
23382
+ * @private
23383
+ * @function
23384
+ * @param {Boolean} [propagate=true] Whether to propagate updated headers to existing tiles and queued image loader jobs.
23385
+ */
23386
+ _updateAjaxHeaders: function(propagate) {
23387
+ if (propagate === undefined) {
23388
+ propagate = true;
23389
+ }
23390
+
23391
+ // merge with viewer's headers
23392
+ if ($.isPlainObject(this.viewer.ajaxHeaders)) {
23393
+ this.ajaxHeaders = $.extend({}, this.viewer.ajaxHeaders,
23394
+ this._ownAjaxHeaders);
23395
+ } else {
23396
+ this.ajaxHeaders = this._ownAjaxHeaders;
23397
+ }
23398
+
23399
+ // propagate header updates to all tiles and queued image loader jobs
23400
+ if (propagate) {
23401
+ var numTiles, xMod, yMod, tile;
23402
+
23403
+ for (var level in this.tilesMatrix) {
23404
+ numTiles = this.source.getNumTiles(level);
23405
+
23406
+ for (var x in this.tilesMatrix[level]) {
23407
+ xMod = (numTiles.x + (x % numTiles.x)) % numTiles.x;
23408
+
23409
+ for (var y in this.tilesMatrix[level][x]) {
23410
+ yMod = (numTiles.y + (y % numTiles.y)) % numTiles.y;
23411
+ tile = this.tilesMatrix[level][x][y];
23412
+
23413
+ tile.loadWithAjax = this.loadTilesWithAjax;
23414
+ if (tile.loadWithAjax) {
23415
+ var tileAjaxHeaders = this.source.getTileAjaxHeaders(level,
23416
+ xMod, yMod);
23417
+ tile.ajaxHeaders = $.extend({}, this.ajaxHeaders,
23418
+ tileAjaxHeaders);
23419
+ } else {
23420
+ tile.ajaxHeaders = null;
23421
+ }
23422
+ }
23423
+ }
23424
+ }
23425
+
23426
+ for (var i = 0; i < this._imageLoader.jobQueue.length; i++) {
23427
+ var job = this._imageLoader.jobQueue[i];
23428
+ job.loadWithAjax = job.tile.loadWithAjax;
23429
+ job.ajaxHeaders = job.tile.loadWithAjax ?
23430
+ job.tile.ajaxHeaders :
23431
+ null;
23432
+ }
23433
+ }
23434
+ },
23435
+
22911
23436
  // private
22912
23437
  _setScale: function(scale, immediately) {
22913
23438
  var sameTarget = (this._scaleSpring.target.value === scale);
@@ -23542,6 +24067,8 @@ function OpenSeadragon(options) {
23542
24067
  tile.loading = false;
23543
24068
  tile.exists = false;
23544
24069
  return;
24070
+ } else {
24071
+ tile.exists = true;
23545
24072
  }
23546
24073
 
23547
24074
  if (time < this.lastResetTime) {
@@ -23578,9 +24105,15 @@ function OpenSeadragon(options) {
23578
24105
  */
23579
24106
  _setTileLoaded: function(tile, data, cutoff, tileRequest) {
23580
24107
  var increment = 0,
24108
+ eventFinished = false,
23581
24109
  _this = this;
23582
24110
 
23583
24111
  function getCompletionCallback() {
24112
+ if (eventFinished) {
24113
+ $.console.error(
24114
+ 'Event \'tile-loaded\' argument getCompletionCallback must be called synchronously. ' +
24115
+ 'Its return value should be called asynchronously.');
24116
+ }
23584
24117
  increment++;
23585
24118
  return completionCallback;
23586
24119
  }
@@ -23622,6 +24155,8 @@ function OpenSeadragon(options) {
23622
24155
  * marked as entirely loaded when the callback has been called once for each
23623
24156
  * call to getCompletionCallback.
23624
24157
  */
24158
+
24159
+ var fallbackCompletion = getCompletionCallback();
23625
24160
  this.viewer.raiseEvent('tile-loaded', {
23626
24161
  tile: tile,
23627
24162
  tiledImage: this,
@@ -23634,8 +24169,9 @@ function OpenSeadragon(options) {
23634
24169
  data: data,
23635
24170
  getCompletionCallback: getCompletionCallback,
23636
24171
  });
24172
+ eventFinished = true;
23637
24173
  // In case the completion callback is never called, we at least force it once.
23638
- getCompletionCallback()();
24174
+ fallbackCompletion();
23639
24175
  },
23640
24176
 
23641
24177
  /**
@@ -23734,6 +24270,7 @@ function OpenSeadragon(options) {
23734
24270
  return false;
23735
24271
  },
23736
24272
 
24273
+
23737
24274
  /**
23738
24275
  * @private
23739
24276
  * @inner
@@ -23883,6 +24420,9 @@ function OpenSeadragon(options) {
23883
24420
  if (sketchScale) {
23884
24421
  clipPoint = clipPoint.times(sketchScale);
23885
24422
  }
24423
+ if (sketchTranslate) {
24424
+ clipPoint = clipPoint.plus(sketchTranslate);
24425
+ }
23886
24426
  return clipPoint;
23887
24427
  });
23888
24428
  });
@@ -24147,6 +24687,7 @@ function OpenSeadragon(options) {
24147
24687
  },
24148
24688
  });
24149
24689
 
24690
+
24150
24691
  /**
24151
24692
  * @private
24152
24693
  * @inner