diff --git a/.eslintrc.hound.json b/.eslintrc.hound.json index 027542f4..9f651a1b 100644 --- a/.eslintrc.hound.json +++ b/.eslintrc.hound.json @@ -278,8 +278,9 @@ ] }, "globals": { - "OpenSeadragon": true, - "define": false, - "module": false + "OpenSeadragon": "writable", + "define": "readonly", + "module": "readonly", + "Map": "readonly" } } diff --git a/.eslintrc.json b/.eslintrc.json index e3495e52..75715c85 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,9 +17,10 @@ } }, "globals": { - "OpenSeadragon": true, - "define": false, - "module": false + "OpenSeadragon": "writable", + "define": "readonly", + "module": "readonly", + "Map": "readonly" }, "rules": { "no-unused-vars": [ diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index a2f8957c..50fdd83b 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,9 +1,9 @@ # These are supported funding model platforms -github: iangilman -patreon: iangilman -open_collective: # Replace with a single Open Collective username -ko_fi: iangilman +github: # iangilman +patreon: # iangilman +open_collective: openseadragon +ko_fi: # iangilman tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username diff --git a/changelog.txt b/changelog.txt index e3c57618..58cf8804 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,7 +7,7 @@ OPENSEADRAGON CHANGELOG * BREAKING CHANGE: Removed deprecated OpenSeadragon.getEvent function (#1949 @msalsbery) * DEPRECATION: MouseTracker exitHandler deprecated for name change to leaveHandler for consistency with DOM event names (#1872 @msalsbery) * Now when "simple image" tile sources are removed from the viewer, they free the memory used by the pyramid they create (#1789 @TakumaKira) -* Documentation fix (#1814 @kenanchristian) +* Improvements to docs (#1814 @kenanchristian, #1872 @msalsbery, #1996 @tdiprima) * Better cleanup on destruction, to avoid memory leaks (#1832 @JoFrMueller) * Better handle destruction when navigator in custom location (#1884 @woodchuck) * Miscellaneous code cleanup (#1840 @msalsbery) @@ -33,7 +33,6 @@ OPENSEADRAGON CHANGELOG * Added OpenSeadragon.setElementPointerEventsNone() for setting pointer-events:'none' on DOM elements (#1872 @msalsbery) * MouseTracker: added contextMenuHandler option for handling contextmenu events (#1872 @msalsbery) * Viewer: added a canvas-contextmenu event (#1872 @msalsbery) -* Added additional documentation for the zoomPerSecond viewer option (#1872 @msalsbery) * Fixed simulated drag events in navigator tests (#1949 @msalsbery) * Added preventDefault option to MouseTracker.contextMenuHandler and Viewer 'canvas-contextmenu' event args (#1951 @msalsbery) * MouseTracker: Added preProcessEventHandler for keydown, keyup, keypress, focus, blur Events (#1951 @msalsbery) @@ -51,6 +50,11 @@ OPENSEADRAGON CHANGELOG * MouseTracker: Added workaround for WebKit Pointer Event Implicit Capture Bug (#1972 @msalsbery) * Removed test for move-leave (fly-over, no enter event)...not a valid, handleable event state, no longer supported (#1972 @msalsbery) * Added OpenSeadragon.setElementPointerEvents() for setting pointer-events to other values besides 'none' on DOM elements (#1972 @msalsbery) +* Now ensuring the page body is display:block when in fullscreen (#1995 @thewilkybarkid) +* Added a static method in OpenSeadragon to get an existing viewer (#2000 @HerCerM) +* Now ensuring that the new item is already in the navigator when the "add-item" event fires (#2005 @RammasEchor) +* Added keys to change image in sequence mode (j: previous, k: next) (#2007 @RammasEchor) +* Fixed a bug where the navigator wouldn't pick up opacity/composite changes made while it is loading (#2018 @crydell) 2.4.2: diff --git a/package-lock.json b/package-lock.json index 42bff69d..44260921 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4069,9 +4069,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-root": { diff --git a/package.json b/package.json index 54131a7e..4f5e033f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "osm", "tms" ], - "homepage": "http://openseadragon.github.io/", + "homepage": "https://openseadragon.github.io/", + "funding": "https://opencollective.com/openseadragon", "bugs": { "url": "https://github.com/openseadragon/openseadragon/issues" }, diff --git a/src/navigator.js b/src/navigator.js index 5414a53e..81993b74 100644 --- a/src/navigator.js +++ b/src/navigator.js @@ -404,6 +404,8 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /* var myItem = event.item; myItem._originalForNavigator = original; _this._matchBounds(myItem, original, true); + _this._matchOpacity(myItem, original); + _this._matchCompositeOperation(myItem, original); function matchBounds() { _this._matchBounds(myItem, original); diff --git a/src/openseadragon.js b/src/openseadragon.js index 80458437..f6c9e756 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -195,8 +195,9 @@ * * @property {String} [compositeOperation=null] * Valid values are 'source-over', 'source-atop', 'source-in', 'source-out', - * 'destination-over', 'destination-atop', 'destination-in', - * 'destination-out', 'lighter', 'copy' or 'xor' + * 'destination-over', 'destination-atop', 'destination-in', 'destination-out', + * 'lighter', 'difference', 'copy', 'xor', etc. + * For complete list of modes, please @see {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation/ globalCompositeOperation} * * @property {Boolean} [imageSmoothingEnabled=true] * Image smoothing for canvas rendering (only if canvas is used). Note: Ignored @@ -1402,6 +1403,26 @@ function OpenSeadragon( options ){ CHROMEEDGE: 7 }, + /** + * Keep track of which {@link Viewer}s have been created. + * - Key: {@link Element} to which a Viewer is attached. + * - Value: {@link Viewer} of the element defined by the key. + * @private + * @static + * @type {Object} + */ + _viewers: new Map(), + + /** + * Returns the {@link Viewer} attached to a given DOM element. If there is + * no viewer attached to the provided element, undefined is returned. + * @function + * @param {String|Element} element Accepts an id or element. + * @returns {Viewer} The viewer attached to the given element, or undefined. + */ + getViewer: function(element) { + return $._viewers.get(this.getElement(element)); + }, /** * Returns a DOM Element for the given id or element. diff --git a/src/viewer.js b/src/viewer.js index ab0443cb..2aaa29a6 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -481,6 +481,8 @@ $.Viewer = function( options ) { this.drawer.setImageSmoothingEnabled(this.imageSmoothingEnabled); } + // Register the viewer + $._viewers.set(this.element, this); }; $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, /** @lends OpenSeadragon.Viewer.prototype */{ @@ -824,6 +826,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, this.canvas = null; this.container = null; + // Unregister the viewer + $._viewers.delete(this.element); + // clear our reference to the main element - they will need to pass it in again, creating a new viewer this.element = null; }, @@ -1000,6 +1005,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, bodyStyle.height = "100%"; docStyle.height = "100%"; + this.bodyDisplay = bodyStyle.display; + bodyStyle.display = "block"; + //when entering full screen on the ipad it wasn't sufficient to leave //the body intact as only only the top half of the screen would //respond to touch events on the canvas, while the bottom half treated @@ -1064,6 +1072,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, bodyStyle.height = this.bodyHeight; docStyle.height = this.docHeight; + bodyStyle.display = this.bodyDisplay; + body.removeChild( this.element ); nodes = this.previousBody.length; for ( i = 0; i < nodes; i++ ) { @@ -1492,6 +1502,17 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, if (_this.collectionMode) { _this.world.setAutoRefigureSizes(false); } + + if (_this.navigator) { + optionsClone = $.extend({}, queueItem.options, { + replace: false, // navigator already removed the layer, nothing to replace + originalTiledImage: tiledImage, + tileSource: queueItem.tileSource + }); + + _this.navigator.addTiledImage(optionsClone); + } + _this.world.addItem( tiledImage, { index: queueItem.options.index }); @@ -1505,16 +1526,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, _this.viewport.goHome(true); } - if (_this.navigator) { - optionsClone = $.extend({}, queueItem.options, { - replace: false, // navigator already removed the layer, nothing to replace - originalTiledImage: tiledImage, - tileSource: queueItem.tileSource - }); - - _this.navigator.addTiledImage(optionsClone); - } - if (queueItem.options.success) { queueItem.options.success({ item: tiledImage @@ -1635,8 +1646,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, ////////////////////////////////////////////////////////////////////////// var onFocusHandler = $.delegate( this, onFocus ), onBlurHandler = $.delegate( this, onBlur ), - onNextHandler = $.delegate( this, onNext ), - onPreviousHandler = $.delegate( this, onPrevious ), + onNextHandler = $.delegate( this, this.goToNextPage ), + onPreviousHandler = $.delegate( this, this.goToPreviousPage ), navImages = this.navImages, useGroup = true; @@ -2305,7 +2316,40 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, this.world.resetItems(); this.forceRedraw(); } - } + }, + + /** + * Sets the image source to the source with index equal to + * currentIndex - 1. Changes current image in sequence mode. + * If specified, wraps around (see navPrevNextWrap in + * {@link OpenSeadragon.Options}) + * + * @method + */ + + goToPreviousPage: function () { + var previous = this._sequenceIndex - 1; + if(this.navPrevNextWrap && previous < 0){ + previous += this.tileSources.length; + } + this.goToPage( previous ); + }, + + /** + * Sets the image source to the source with index equal to + * currentIndex + 1. Changes current image in sequence mode. + * If specified, wraps around (see navPrevNextWrap in + * {@link OpenSeadragon.Options}) + * + * @method + */ + goToNextPage: function () { + var next = this._sequenceIndex + 1; + if(this.navPrevNextWrap && next >= this.tileSources.length){ + next = 0; + } + this.goToPage( next ); + }, }); @@ -2771,6 +2815,12 @@ function onCanvasKeyPress( event ) { this.viewport.toggleFlip(); event.preventDefault = true; break; + case 106: //j - previous image source + this.goToPreviousPage(); + break; + case 107: //k - next image source + this.goToNextPage(); + break; default: // console.log( 'navigator keycode %s', event.keyCode ); event.preventDefault = false; @@ -3660,22 +3710,4 @@ function onFlip() { this.viewport.toggleFlip(); } -function onPrevious(){ - var previous = this._sequenceIndex - 1; - if(this.navPrevNextWrap && previous < 0){ - previous += this.tileSources.length; - } - this.goToPage( previous ); -} - - -function onNext(){ - var next = this._sequenceIndex + 1; - if(this.navPrevNextWrap && next >= this.tileSources.length){ - next = 0; - } - this.goToPage( next ); -} - - }( OpenSeadragon )); diff --git a/test/modules/viewerretrieval.js b/test/modules/viewerretrieval.js new file mode 100644 index 00000000..79c1c7b2 --- /dev/null +++ b/test/modules/viewerretrieval.js @@ -0,0 +1,93 @@ +/* global QUnit, $, testLog */ + +(function() { + var viewer1; + var viewer2; + + QUnit.module('ViewerRetrieval', { + beforeEach: function () { + $('
') + .appendTo("#qunit-fixture"); + + testLog.reset(); + + viewer1 = OpenSeadragon({ + id: 'example1', + prefixUrl: 'build/openseadragon/images/', + springStiffness: 100 // Faster animation = faster tests + }); + + viewer2 = OpenSeadragon({ + id: 'example2', + prefixUrl: 'build/openseadragon/images/', + springStiffness: 100 + }); + }, + + afterEach: function () { + if (viewer1 && viewer1.destroy) { + viewer1.destroy(); + } + if (viewer2 && viewer2.destroy) { + viewer2.destroy(); + } + viewer1 = viewer2 = null; + } + }); + + QUnit.test('Get Viewers by Id', function(assert) { + var retrievedViewer1 = OpenSeadragon.getViewer('example1'); + assert.ok(retrievedViewer1, 'Attached viewer retrieved'); + assert.equal(retrievedViewer1, viewer1, 'Viewers are same instance'); + + var retrievedViewer2 = OpenSeadragon.getViewer('example2'); + assert.ok(retrievedViewer2, 'Attached viewer retrieved'); + assert.equal(retrievedViewer2, viewer2, 'Viewers are same instance'); + + // Internal state + assert.equal(OpenSeadragon._viewers.size, 2, 'Correct amount of viewers'); + }); + + QUnit.test('Get Viewers by Element', function(assert) { + var retrievedViewer1 = OpenSeadragon.getViewer( + document.getElementById('example1')); + assert.ok(retrievedViewer1, 'Attached viewer retrieved'); + assert.equal(retrievedViewer1, viewer1, 'Viewers are same instance'); + + var retrievedViewer2 = OpenSeadragon.getViewer( + document.getElementById('example2')); + assert.ok(retrievedViewer2, 'Attached viewer retrieved'); + assert.equal(retrievedViewer2, viewer2, 'Viewers are same instance'); + + // Internal state + assert.equal(OpenSeadragon._viewers.size, 2, 'Correct amount of viewers'); + }); + + QUnit.test('Undefined on Get Non-Existent Viewer by Id', function(assert) { + var notFoundViewer = OpenSeadragon.getViewer('no-viewer'); + assert.equal(notFoundViewer, undefined, "Not found viewer is undefined"); + }); + + QUnit.test('Undefined on Get Non-Existent Viewer by Element', function(assert) { + var element = document.createElement('div'); + element.id = 'no-viewer'; + document.body.appendChild(element); + + var notFoundViewer = OpenSeadragon.getViewer(element); + assert.equal(notFoundViewer, undefined, "Not found viewer is undefined"); + }); + + QUnit.test('Cleanup Viewers Registration', function(assert) { + viewer1.destroy(); + viewer2.destroy(); + viewer1 = viewer2 = null; + + var retrievedViewer1 = OpenSeadragon.getViewer('example1'); + var retrievedViewer2 = OpenSeadragon.getViewer('example2'); + assert.equal(retrievedViewer1, undefined, 'Viewer was destroyed'); + assert.equal(retrievedViewer2, undefined, 'Viewer was destroyed'); + + // Internal state + assert.equal(OpenSeadragon._viewers.size, 0, 'No viewers are registered'); + }); +})(); diff --git a/test/test.html b/test/test.html index c740b01c..f971a257 100644 --- a/test/test.html +++ b/test/test.html @@ -22,6 +22,7 @@ +