Merge pull request #2346 from uschmidt83/ajax-headers

Add `setAjaxHeaders` method to Viewer and TiledImage
This commit is contained in:
Ian Gilman 2023-05-19 15:01:54 -07:00 committed by GitHub
commit e6f2d3e07b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 273 additions and 8 deletions

View File

@ -115,7 +115,7 @@ $.ButtonGroup.prototype = {
/**
* Adds the given button to this button group.
*
* @functions
* @function
* @param {OpenSeadragon.Button} button
*/
addButton: function( button ){

View File

@ -147,6 +147,9 @@ $.TiledImage = function( options ) {
var degrees = options.degrees || 0;
delete options.degrees;
var ajaxHeaders = options.ajaxHeaders;
delete options.ajaxHeaders;
$.extend( true, this, {
//internal state properties
@ -238,6 +241,9 @@ $.TiledImage = function( options ) {
tiledImage: _this
}, args));
};
this._ownAjaxHeaders = {};
this.setAjaxHeaders(ajaxHeaders, false);
};
$.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{
@ -1003,6 +1009,90 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
});
},
/**
* Update headers to include when making AJAX requests.
*
* Unless `propagate` is set to false (which is likely only useful in rare circumstances),
* the updated headers are propagated to all tiles and queued image loader jobs.
*
* Note that the rules for merging headers still apply, i.e. headers returned by
* {@link OpenSeadragon.TileSource#getTileAjaxHeaders} take precedence over
* the headers here in the tiled image (`TiledImage.ajaxHeaders`).
*
* @function
* @param {Object} ajaxHeaders Updated AJAX headers, which will be merged over any headers specified in {@link OpenSeadragon.Options}.
* @param {Boolean} [propagate=true] Whether to propagate updated headers to existing tiles and queued image loader jobs.
*/
setAjaxHeaders: function(ajaxHeaders, propagate) {
if (ajaxHeaders === null) {
ajaxHeaders = {};
}
if (!$.isPlainObject(ajaxHeaders)) {
console.error('[TiledImage.setAjaxHeaders] Ignoring invalid headers, must be a plain object');
return;
}
this._ownAjaxHeaders = ajaxHeaders;
this._updateAjaxHeaders(propagate);
},
/**
* Update headers to include when making AJAX requests.
*
* This function has the same effect as calling {@link OpenSeadragon.TiledImage#setAjaxHeaders},
* except that the headers for this tiled image do not change. This is especially useful
* for propagating updated headers from {@link OpenSeadragon.TileSource#getTileAjaxHeaders}
* to existing tiles.
*
* @private
* @function
* @param {Boolean} [propagate=true] Whether to propagate updated headers to existing tiles and queued image loader jobs.
*/
_updateAjaxHeaders: function(propagate) {
if (propagate === undefined) {
propagate = true;
}
// merge with viewer's headers
if ($.isPlainObject(this.viewer.ajaxHeaders)) {
this.ajaxHeaders = $.extend({}, this.viewer.ajaxHeaders, this._ownAjaxHeaders);
} else {
this.ajaxHeaders = this._ownAjaxHeaders;
}
// propagate header updates to all tiles and queued image loader jobs
if (propagate) {
var numTiles, xMod, yMod, tile;
for (var level in this.tilesMatrix) {
numTiles = this.source.getNumTiles(level);
for (var x in this.tilesMatrix[level]) {
xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;
for (var y in this.tilesMatrix[level][x]) {
yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;
tile = this.tilesMatrix[level][x][y];
tile.loadWithAjax = this.loadTilesWithAjax;
if (tile.loadWithAjax) {
var tileAjaxHeaders = this.source.getTileAjaxHeaders( level, xMod, yMod );
tile.ajaxHeaders = $.extend({}, this.ajaxHeaders, tileAjaxHeaders);
} else {
tile.ajaxHeaders = null;
}
}
}
}
for (var i = 0; i < this._imageLoader.jobQueue.length; i++) {
var job = this._imageLoader.jobQueue[i];
job.loadWithAjax = job.tile.loadWithAjax;
job.ajaxHeaders = job.tile.loadWithAjax ? job.tile.ajaxHeaders : null;
}
}
},
// private
_setScale: function(scale, immediately) {
var sameTarget = (this._scaleSpring.target.value === scale);

View File

@ -663,6 +663,11 @@ $.TileSource.prototype = {
* The headers returned here will override headers specified at the Viewer or TiledImage level.
* Specifying a falsy value for a header will clear its existing value set at the Viewer or
* TiledImage level (if any).
*
* Note that the headers of existing tiles don't automatically change when this function
* returns updated headers. To do that, you need to call {@link OpenSeadragon.Viewer#setAjaxHeaders}
* and propagate the changes.
*
* @function
* @param {Number} level
* @param {Number} x

View File

@ -966,7 +966,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
* Turns debugging mode on or off for this viewer.
*
* @function
* @param {Boolean} true to turn debug on, false to turn debug off.
* @param {Boolean} debugMode true to turn debug on, false to turn debug off.
*/
setDebugMode: function(debugMode){
@ -978,10 +978,57 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
this.forceRedraw();
},
/**
* Update headers to include when making AJAX requests.
*
* Unless `propagate` is set to false (which is likely only useful in rare circumstances),
* the updated headers are propagated to all tiled images, each of which will subsequently
* propagate the changed headers to all their tiles.
* If applicable, the headers of the viewer's navigator and reference strip will also be updated.
*
* Note that the rules for merging headers still apply, i.e. headers returned by
* {@link OpenSeadragon.TileSource#getTileAjaxHeaders} take precedence over
* `TiledImage.ajaxHeaders`, which take precedence over the headers here in the viewer.
*
* @function
* @param {Object} ajaxHeaders Updated AJAX headers.
* @param {Boolean} [propagate=true] Whether to propagate updated headers to tiled images, etc.
*/
setAjaxHeaders: function(ajaxHeaders, propagate) {
if (ajaxHeaders === null) {
ajaxHeaders = {};
}
if (!$.isPlainObject(ajaxHeaders)) {
console.error('[Viewer.setAjaxHeaders] Ignoring invalid headers, must be a plain object');
return;
}
if (propagate === undefined) {
propagate = true;
}
this.ajaxHeaders = ajaxHeaders;
if (propagate) {
for (var i = 0; i < this.world.getItemCount(); i++) {
this.world.getItemAt(i)._updateAjaxHeaders(true);
}
if (this.navigator) {
this.navigator.setAjaxHeaders(this.ajaxHeaders, true);
}
if (this.referenceStrip && this.referenceStrip.miniViewers) {
for (var key in this.referenceStrip.miniViewers) {
this.referenceStrip.miniViewers[key].setAjaxHeaders(this.ajaxHeaders, true);
}
}
}
},
/**
* Adds the given button to this viewer.
*
* @functions
* @function
* @param {OpenSeadragon.Button} button
*/
addButton: function( button ){
@ -1402,7 +1449,6 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
* A set of headers to include when making tile AJAX requests.
* Note that these headers will be merged over any headers specified in {@link OpenSeadragon.Options}.
* Specifying a falsy value for a header will clear its existing value set at the Viewer level (if any).
* requests.
* @param {Function} [options.success] A function that gets called when the image is
* successfully added. It's passed the event object which contains a single property:
* "item", which is the resulting instance of TiledImage.
@ -1450,10 +1496,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
if (options.loadTilesWithAjax === undefined) {
options.loadTilesWithAjax = this.loadTilesWithAjax;
}
if (options.ajaxHeaders === undefined || options.ajaxHeaders === null) {
options.ajaxHeaders = this.ajaxHeaders;
} else if ($.isPlainObject(options.ajaxHeaders) && $.isPlainObject(this.ajaxHeaders)) {
options.ajaxHeaders = $.extend({}, this.ajaxHeaders, options.ajaxHeaders);
if (!$.isPlainObject(options.ajaxHeaders)) {
options.ajaxHeaders = {};
}
var myQueueItem = {

View File

@ -245,4 +245,130 @@
tileSource: staticHeaderTileSource
});
});
QUnit.test('Viewer headers can be updated', function(assert) {
var done = assert.async();
var newHeaders = {
'X-Viewer-Header': 'ViewerHeaderValue-Updated',
'X-Viewer-Header2': 'ViewerHeaderValue2'
}
var newHeaders2 = {
Range: 'test',
}
var tileLoaded = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded);
// set new Viewer headers and propagate to TiledImage and Tile
viewer.setAjaxHeaders(newHeaders);
viewer.addHandler('tile-loaded', tileLoaded2);
};
var tileLoaded2 = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded2);
assert.deepEqual(viewer.ajaxHeaders, newHeaders);
assert.deepEqual(evt.tiledImage.ajaxHeaders, newHeaders);
assert.deepEqual(
evt.tile.ajaxHeaders,
OpenSeadragon.extend(
{}, viewer.ajaxHeaders, evt.tiledImage.ajaxHeaders,
{ Range: getTileRangeHeader(evt.tile.level, evt.tile.x, evt.tile.y) }
)
);
// set new Viewer headers and propagate to TiledImage and Tile
viewer.setAjaxHeaders(newHeaders2, true);
viewer.addHandler('tile-loaded', tileLoaded3);
};
var tileLoaded3 = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded3);
assert.deepEqual(viewer.ajaxHeaders, newHeaders2);
assert.deepEqual(evt.tiledImage.ajaxHeaders, newHeaders2);
assert.equal(evt.tile.ajaxHeaders['X-Viewer-Header'], undefined);
assert.equal(evt.tile.ajaxHeaders['X-Viewer-Header2'], undefined);
// 'Range' header entry set per tile and must not be overwritten by Viewer header
assert.equal(evt.tile.ajaxHeaders.Range, getTileRangeHeader(evt.tile.level, evt.tile.x, evt.tile.y));
// set new Viewer headers but do not propagate to TiledImage and Tile
viewer.setAjaxHeaders(newHeaders, false);
viewer.addHandler('tile-loaded', tileLoaded4);
};
var tileLoaded4 = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded4);
assert.deepEqual(viewer.ajaxHeaders, newHeaders);
assert.deepEqual(evt.tiledImage.ajaxHeaders, newHeaders2);
assert.equal(evt.tile.ajaxHeaders['X-Viewer-Header'], undefined);
assert.equal(evt.tile.ajaxHeaders['X-Viewer-Header2'], undefined);
done();
};
viewer.addHandler('tile-loaded', tileLoaded);
viewer.open(customTileSource);
});
QUnit.test('TiledImage headers can be updated', function(assert) {
var done = assert.async();
var tileSourceHeaders = {
'X-Tile-Header': 'TileHeaderValue'
}
var newHeaders = {
'X-TiledImage-Header': 'TiledImageHeaderValue-Updated',
'X-TiledImage-Header2': 'TiledImageHeaderValue2'
}
var newHeaders2 = {
'X-Viewer-Header': 'ViewerHeaderValue-Updated',
'X-Tile-Header': 'TileHeaderValue-Updated'
}
var tileLoaded = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded);
// set new TiledImage headers and propagate to Tile
evt.tiledImage.setAjaxHeaders(newHeaders);
viewer.addHandler('tile-loaded', tileLoaded2);
};
var tileLoaded2 = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded2);
assert.deepEqual(viewer.ajaxHeaders, { 'X-Viewer-Header': 'ViewerHeaderValue' });
assert.deepEqual(evt.tiledImage._ownAjaxHeaders, newHeaders);
assert.deepEqual(evt.tiledImage.ajaxHeaders, OpenSeadragon.extend({}, viewer.ajaxHeaders, newHeaders));
assert.deepEqual(evt.tile.ajaxHeaders, OpenSeadragon.extend({}, viewer.ajaxHeaders, newHeaders, tileSourceHeaders));
// set new TiledImage headers (that overwrite header entries of Viewer and Tile) and propagate to Tile
evt.tiledImage.setAjaxHeaders(newHeaders2, true);
viewer.addHandler('tile-loaded', tileLoaded3);
};
var tileLoaded3 = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded3);
assert.deepEqual(viewer.ajaxHeaders, { 'X-Viewer-Header': 'ViewerHeaderValue' });
assert.deepEqual(evt.tiledImage._ownAjaxHeaders, newHeaders2);
assert.deepEqual(evt.tiledImage.ajaxHeaders, OpenSeadragon.extend({}, viewer.ajaxHeaders, newHeaders2));
assert.deepEqual(evt.tile.ajaxHeaders, OpenSeadragon.extend({}, viewer.ajaxHeaders, newHeaders2, tileSourceHeaders));
// set new TiledImage headers but do not propagate to Tile
evt.tiledImage.setAjaxHeaders(null, false);
viewer.addHandler('tile-loaded', tileLoaded4);
};
var tileLoaded4 = function tileLoaded(evt) {
viewer.removeHandler('tile-loaded', tileLoaded4);
assert.deepEqual(viewer.ajaxHeaders, { 'X-Viewer-Header': 'ViewerHeaderValue' });
assert.deepEqual(evt.tiledImage._ownAjaxHeaders, {});
assert.deepEqual(evt.tiledImage.ajaxHeaders, viewer.ajaxHeaders);
assert.deepEqual(evt.tile.ajaxHeaders, OpenSeadragon.extend({}, viewer.ajaxHeaders, newHeaders2, tileSourceHeaders));
done();
};
viewer.addHandler('tile-loaded', tileLoaded);
viewer.addTiledImage({
ajaxHeaders: {
'X-TiledImage-Header': 'TiledImageHeaderValue'
},
tileSource: OpenSeadragon.extend({}, customTileSource, {
getTileAjaxHeaders: function() {
return tileSourceHeaders;
}
}),
});
});
})();