diff --git a/src/imageloader.js b/src/imageloader.js index cd654722..60f3ba2a 100644 --- a/src/imageloader.js +++ b/src/imageloader.js @@ -32,15 +32,26 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -(function( $ ){ +(function($){ -// private class -function ImageJob ( options ) { +/** + * @private + * @class ImageJob + * @classdesc Handles downloading of a single image. + * @param {Object} options - Options for this ImageJob. + * @param {String} [options.src] - URL of image to download. + * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. + * @param {String} [options.headers] - Headers to add to the image request. + * @param {String} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {Function} [options.callback] - Called once image has been downloaded. + * @param {Function} [options.abort] - Called when this image job is aborted. + */ +function ImageJob (options) { - $.extend( true, this, { - timeout: $.DEFAULT_SETTINGS.timeout, - jobId: null - }, options ); + $.extend(true, this, { + timeout: $.DEFAULT_SETTINGS.timeout, + jobId: null + }, options); /** * Image object which will contain downloaded image. @@ -52,42 +63,86 @@ function ImageJob ( options ) { ImageJob.prototype = { errorMsg: null, + + /** + * Starts the image job. + * @method + */ start: function(){ - var _this = this; + var self = this; + var selfAbort = this.abort; this.image = new Image(); - if ( this.crossOriginPolicy !== false ) { - this.image.crossOrigin = this.crossOriginPolicy; - } - this.image.onload = function(){ - _this.finish( true ); + self.finish(true); }; - this.image.onabort = this.image.onerror = function(){ - _this.errorMsg = "Image load aborted"; - _this.finish( false ); + this.image.onabort = this.image.onerror = function() { + self.errorMsg = "Image load aborted"; + self.finish(false); }; - this.jobId = window.setTimeout( function(){ - _this.errorMsg = "Image load exceeded timeout"; - _this.finish( false ); + this.jobId = window.setTimeout(function(){ + self.errorMsg = "Image load exceeded timeout"; + self.finish(false); }, this.timeout); - this.image.src = this.src; + // Load the tile with an AJAX request if the loadWithAjax option is + // set. Otherwise load the image by setting the source proprety of the image object. + if (this.loadWithAjax) { + this.request = $.makeAjaxRequest({ + url: this.src, + withCredentials: this.ajaxWithCredentials, + headers: this.headers, + responseType: "arraybuffer", + success: function(request) { + // Make the raw data into a blob + var blb = new window.Blob([request.response]); + // If the blob is empty for some reason consider the image load a failure. + if (blb.size === 0) { + self.errorMsg = "Empty image response."; + self.finish(false); + } + // Create a URL for the blob data and make it the source of the image object. + // This will still trigger Image.onload to indicate a successful tile load. + var url = (window.URL || window.webkitURL).createObjectURL(blb); + self.image.src = url; + }, + error: function(request) { + self.errorMsg = "Image load aborted - XHR error"; + self.finish(false); + } + }); + + // Provide a function to properly abort the request. + this.abort = function() { + self.request.abort(); + + // Call the existing abort function if available + if (typeof selfAbort === "function") { + selfAbort(); + } + }; + } else { + if (this.crossOriginPolicy !== false) { + this.image.crossOrigin = this.crossOriginPolicy; + } + + this.image.src = this.src; + } }, - finish: function( successful ) { + finish: function(successful) { this.image.onload = this.image.onerror = this.image.onabort = null; if (!successful) { this.image = null; } - if ( this.jobId ) { - window.clearTimeout( this.jobId ); + if (this.jobId) { + window.clearTimeout(this.jobId); } - this.callback( this ); + this.callback(this); } }; @@ -100,13 +155,13 @@ ImageJob.prototype = { * @param {Object} options - Options for this ImageLoader. * @param {Number} [options.jobLimit] - The number of concurrent image requests. See imageLoaderLimit in {@link OpenSeadragon.Options} for details. */ -$.ImageLoader = function( options ) { +$.ImageLoader = function(options) { - $.extend( true, this, { + $.extend(true, this, { jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit, jobQueue: [], jobsInProgress: 0 - }, options ); + }, options); }; @@ -116,22 +171,31 @@ $.ImageLoader.prototype = { /** * Add an unloaded image to the loader queue. * @method - * @param {String} src - URL of image to download. - * @param {String} crossOriginPolicy - CORS policy to use for downloads - * @param {Function} callback - Called once image has been downloaded. + * @param {Object} options - Options for this job. + * @param {String} [options.src] - URL of image to download. + * @param {String} [options.loadWithAjax] - Whether to load this image with AJAX. + * @param {String} [options.headers] - Headers to add to the image request. + * @param {String|Boolean} [options.crossOriginPolicy] - CORS policy to use for downloads + * @param {Boolean} [options.ajaxWithCredentials] - Whether to set withCredentials on AJAX + * requests. + * @param {Function} [options.callback] - Called once image has been downloaded. + * @param {Function} [options.abort] - Called when this image job is aborted. */ - addJob: function( options ) { + addJob: function(options) { var _this = this, - complete = function( job ) { - completeJob( _this, job, options.callback ); + complete = function(job) { + completeJob(_this, job, options.callback); }, jobOptions = { src: options.src, + loadWithAjax: options.loadWithAjax, + headers: options.loadWithAjax ? options.headers : null, crossOriginPolicy: options.crossOriginPolicy, + ajaxWithCredentials: options.ajaxWithCredentials, callback: complete, abort: options.abort }, - newJob = new ImageJob( jobOptions ); + newJob = new ImageJob(jobOptions); if ( !this.jobLimit || this.jobsInProgress < this.jobLimit ) { newJob.start(); @@ -166,18 +230,18 @@ $.ImageLoader.prototype = { * @param job - The ImageJob that has completed. * @param callback - Called once cleanup is finished. */ -function completeJob( loader, job, callback ) { +function completeJob(loader, job, callback) { var nextJob; loader.jobsInProgress--; - if ( (!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) { + if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) { nextJob = loader.jobQueue.shift(); nextJob.start(); loader.jobsInProgress++; } - callback( job.image, job.errorMsg ); + callback(job.image, job.errorMsg, job.request); } -}( OpenSeadragon )); +}(OpenSeadragon)); diff --git a/src/openseadragon.js b/src/openseadragon.js index a470de14..59f2ffac 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -584,9 +584,16 @@ * not use CORS, and the canvas will be tainted. * * @property {Boolean} [ajaxWithCredentials=false] - * Whether to set the withCredentials XHR flag for AJAX requests (when loading tile sources). + * Whether to set the withCredentials XHR flag for AJAX requests. * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level. * + * @property {Boolean} [loadTilesWithAjax=false] + * Whether to load tile data using AJAX requests. + * Note that this can be overridden at the {@link OpenSeadragon.TileSource} level. + * + * @property {Object} [ajaxRequestHeaders={}] + * A set of headers to include when making AJAX requests for tile sources or tiles. + * */ /** @@ -1005,6 +1012,8 @@ function OpenSeadragon( options ){ initialPage: 0, crossOriginPolicy: false, ajaxWithCredentials: false, + loadTilesWithAjax: false, + ajaxRequestHeaders: {}, //PAN AND ZOOM SETTINGS AND CONSTRAINTS panHorizontal: true, @@ -2120,11 +2129,16 @@ function OpenSeadragon( options ){ * @param {String} options.url - the url to request * @param {Function} options.success - a function to call on a successful response * @param {Function} options.error - a function to call on when an error occurs + * @param {Object} options.headers - headers to add to the AJAX request + * @param {String} options.responseType - the response type of the the AJAX request * @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials * @throws {Error} + * @returns {XMLHttpRequest} */ makeAjaxRequest: function( url, onSuccess, onError ) { var withCredentials; + var headers; + var responseType; // Note that our preferred API is that you pass in a single object; the named // arguments are for legacy support. @@ -2132,6 +2146,8 @@ function OpenSeadragon( options ){ onSuccess = url.success; onError = url.error; withCredentials = url.withCredentials; + headers = url.headers; + responseType = url.responseType || null; url = url.url; } @@ -2147,9 +2163,9 @@ function OpenSeadragon( options ){ if ( request.readyState == 4 ) { request.onreadystatechange = function(){}; - // With protocols other than http/https, the status is 200 + // With protocols other than http/https, the status is in [200, 300) // on Firefox and 0 on other browsers - if ( request.status === 200 || + if ( (request.status >= 200 && request.status < 300) || ( request.status === 0 && protocol !== "http:" && protocol !== "https:" )) { @@ -2167,11 +2183,21 @@ function OpenSeadragon( options ){ try { request.open( "GET", url, true ); + if (responseType) { + request.responseType = responseType; + } + + if (headers) { + Object.keys(headers).forEach(function (headerName) { + request.setRequestHeader(headerName, headers[headerName]); + }); + } + if (withCredentials) { request.withCredentials = true; } - request.send( null ); + request.send(null); } catch (e) { var msg = e.message; @@ -2231,6 +2257,8 @@ function OpenSeadragon( options ){ } } } + + return request; }, /** diff --git a/src/tile.js b/src/tile.js index 72776aac..2dd2b95e 100644 --- a/src/tile.js +++ b/src/tile.js @@ -47,8 +47,10 @@ * @param {String} url The URL of this tile's image. * @param {CanvasRenderingContext2D} context2D The context2D of this tile if it * is provided directly by the tile source. + * @param {Boolean} loadWithAjax Whether this tile image should be loaded with an AJAX request . + * @param {Object} headers The headers to send with this tile's AJAX request (if applicable). */ -$.Tile = function(level, x, y, bounds, exists, url, context2D) { +$.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, headers) { /** * The zoom level this tile belongs to. * @member {Number} level @@ -91,6 +93,29 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D) { * @memberOf OpenSeadragon.Tile# */ this.context2D = context2D; + /** + * Whether to load this tile's image with an AJAX request. + * @member {Boolean} loadWithAjax + * @memberof OpenSeadragon.Tile# + */ + this.loadWithAjax = loadWithAjax; + /** + * The headers to be used in requesting this tile's image. + * Only used if loadWithAjax is set to true. + * @member {Object} headers + * @memberof OpenSeadragon.Tile# + */ + this.headers = headers; + /** + * The unique cache key for this tile. + * @member {String} cacheKey + * @memberof OpenSeadragon.Tile# + */ + if (this.headers) { + this.cacheKey = this.url + "+" + JSON.stringify(this.headers); + } else { + this.cacheKey = this.url; + } /** * Is this tile loaded? * @member {Boolean} loaded diff --git a/src/tilecache.js b/src/tilecache.js index ee3a4662..6300427f 100644 --- a/src/tilecache.js +++ b/src/tilecache.js @@ -149,16 +149,16 @@ $.TileCache.prototype = { cacheTile: function( options ) { $.console.assert( options, "[TileCache.cacheTile] options is required" ); $.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" ); - $.console.assert( options.tile.url, "[TileCache.cacheTile] options.tile.url is required" ); + $.console.assert( options.tile.cacheKey, "[TileCache.cacheTile] options.tile.cacheKey is required" ); $.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" ); var cutoff = options.cutoff || 0; var insertionIndex = this._tilesLoaded.length; - var imageRecord = this._imagesLoaded[options.tile.url]; + var imageRecord = this._imagesLoaded[options.tile.cacheKey]; if (!imageRecord) { $.console.assert( options.image, "[TileCache.cacheTile] options.image is required to create an ImageRecord" ); - imageRecord = this._imagesLoaded[options.tile.url] = new ImageRecord({ + imageRecord = this._imagesLoaded[options.tile.cacheKey] = new ImageRecord({ image: options.image }); @@ -232,9 +232,9 @@ $.TileCache.prototype = { }, // private - getImageRecord: function(url) { - $.console.assert(url, '[TileCache.getImageRecord] url is required'); - return this._imagesLoaded[url]; + getImageRecord: function(cacheKey) { + $.console.assert(cacheKey, '[TileCache.getImageRecord] cacheKey is required'); + return this._imagesLoaded[cacheKey]; }, // private @@ -246,11 +246,11 @@ $.TileCache.prototype = { tile.unload(); tile.cacheImageRecord = null; - var imageRecord = this._imagesLoaded[tile.url]; + var imageRecord = this._imagesLoaded[tile.cacheKey]; imageRecord.removeTile(tile); if (!imageRecord.getTileCount()) { imageRecord.destroy(); - delete this._imagesLoaded[tile.url]; + delete this._imagesLoaded[tile.cacheKey]; this._imagesLoadedCount--; } diff --git a/src/tiledimage.js b/src/tiledimage.js index 70859ec0..21b9c05c 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -75,6 +75,13 @@ * @param {Boolean} [options.debugMode] - See {@link OpenSeadragon.Options}. * @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}. * @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.ajaxWithCredentials] - See {@link OpenSeadragon.Options}. + * @param {Boolean} [options.loadTilesWithAjax] + * Whether to load tile data using AJAX requests. + * Defaults to the setting in {@link OpenSeadragon.Options}. + * @param {Object} [options.ajaxRequestHeaders={}] + * 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}. */ $.TiledImage = function( options ) { var _this = this; @@ -161,6 +168,7 @@ $.TiledImage = function( options ) { iOSDevice: $.DEFAULT_SETTINGS.iOSDevice, debugMode: $.DEFAULT_SETTINGS.debugMode, crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy, + ajaxWithCredentials: $.DEFAULT_SETTINGS.ajaxWithCredentials, placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle, opacity: $.DEFAULT_SETTINGS.opacity, compositeOperation: $.DEFAULT_SETTINGS.compositeOperation @@ -1179,6 +1187,7 @@ function updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity var tile = getTile( x, y, level, + tiledImage, tiledImage.source, tiledImage.tilesMatrix, currentTime, @@ -1237,7 +1246,7 @@ function updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity if (tile.context2D) { setTileLoaded(tiledImage, tile); } else { - var imageRecord = tiledImage._tileCache.getImageRecord(tile.url); + var imageRecord = tiledImage._tileCache.getImageRecord(tile.cacheKey); if (imageRecord) { var image = imageRecord.getImage(); setTileLoaded(tiledImage, tile, image); @@ -1275,6 +1284,7 @@ function updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity * @param {Number} x * @param {Number} y * @param {Number} level + * @param {OpenSeadragon.TiledImage} tiledImage * @param {OpenSeadragon.TileSource} tileSource * @param {Object} tilesMatrix - A '3d' dictionary [level][x][y] --> Tile. * @param {Number} time @@ -1283,12 +1293,23 @@ function updateTile( tiledImage, haveDrawn, drawLevel, x, y, level, levelOpacity * @param {Number} worldHeight * @returns {OpenSeadragon.Tile} */ -function getTile( x, y, level, tileSource, tilesMatrix, time, numTiles, worldWidth, worldHeight ) { +function getTile( + x, y, + level, + tiledImage, + tileSource, + tilesMatrix, + time, + numTiles, + worldWidth, + worldHeight +) { var xMod, yMod, bounds, exists, url, + headers, context2D, tile; @@ -1305,6 +1326,18 @@ function getTile( x, y, level, tileSource, tilesMatrix, time, numTiles, worldWid bounds = tileSource.getTileBounds( level, xMod, yMod ); exists = tileSource.tileExists( level, xMod, yMod ); url = tileSource.getTileUrl( level, xMod, yMod ); + + // Headers are only applicable if loadTilesWithAjax is set + if (tiledImage.loadTilesWithAjax) { + headers = tileSource.getTileHeaders( level, xMod, yMod ); + // Combine tile headers with global headers (if applicable) + if ($.isPlainObject(tiledImage.ajaxRequestHeaders)) { + headers = $.extend({}, tiledImage.ajaxRequestHeaders, headers); + } + } else { + headers = null; + } + context2D = tileSource.getContext2D ? tileSource.getContext2D(level, xMod, yMod) : undefined; @@ -1318,7 +1351,9 @@ function getTile( x, y, level, tileSource, tilesMatrix, time, numTiles, worldWid bounds, exists, url, - context2D + context2D, + tiledImage.loadTilesWithAjax, + headers ); } @@ -1340,9 +1375,12 @@ function loadTile( tiledImage, tile, time ) { tile.loading = true; tiledImage._imageLoader.addJob({ src: tile.url, + loadWithAjax: tile.loadWithAjax, + headers: tile.headers, crossOriginPolicy: tiledImage.crossOriginPolicy, - callback: function( image, errorMsg ){ - onTileLoad( tiledImage, tile, time, image, errorMsg ); + ajaxWithCredentials: tiledImage.ajaxWithCredentials, + callback: function( image, errorMsg, tileRequest ){ + onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ); }, abort: function() { tile.loading = false; @@ -1359,8 +1397,9 @@ function loadTile( tiledImage, tile, time ) { * @param {Number} time * @param {Image} image * @param {String} errorMsg + * @param {XMLHttpRequest} tileRequest */ -function onTileLoad( tiledImage, tile, time, image, errorMsg ) { +function onTileLoad( tiledImage, tile, time, image, errorMsg, tileRequest ) { if ( !image ) { $.console.log( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg ); /** @@ -1373,8 +1412,15 @@ function onTileLoad( tiledImage, tile, time, image, errorMsg ) { * @property {OpenSeadragon.TiledImage} tiledImage - The tiled image the tile belongs to. * @property {number} time - The time in milliseconds when the tile load began. * @property {string} message - The error message. + * @property {XMLHttpRequest} tileRequest - The XMLHttpRequest used to load the tile if available. */ - tiledImage.viewer.raiseEvent("tile-load-failed", {tile: tile, tiledImage: tiledImage, time: time, message: errorMsg}); + tiledImage.viewer.raiseEvent("tile-load-failed", { + tile: tile, + tiledImage: tiledImage, + time: time, + message: errorMsg, + tileRequest: tileRequest + }); tile.loading = false; tile.exists = false; return; diff --git a/src/tilesource.js b/src/tilesource.js index 135053de..5f058fe9 100644 --- a/src/tilesource.js +++ b/src/tilesource.js @@ -65,6 +65,8 @@ * @param {Boolean} [options.ajaxWithCredentials] * If this TileSource needs to make an AJAX call, this specifies whether to set * the XHR's withCredentials (for accessing secure data). + * @param {Object} [options.ajaxRequestHeaders] + * A set of headers to include in AJAX requests. * @param {Number} [options.width] * Width of the source image at max resolution in pixels. * @param {Number} [options.height] @@ -475,6 +477,7 @@ $.TileSource.prototype = { $.makeAjaxRequest( { url: url, withCredentials: this.ajaxWithCredentials, + headers: this.ajaxRequestHeaders, success: function( xhr ) { var data = processResponse( xhr ); callback( data ); @@ -559,7 +562,7 @@ $.TileSource.prototype = { }, /** - * Responsible for retriving the url which will return an image for the + * Responsible for retrieving the url which will return an image for the * region specified by the given x, y, and level components. * This method is not implemented by this class other than to throw an Error * announcing you have to implement it. Because of the variety of tile @@ -575,6 +578,20 @@ $.TileSource.prototype = { throw new Error( "Method not implemented." ); }, + /** + * Responsible for retrieving the headers which will be attached to the image request for the + * region specified by the given x, y, and level components. + * This option is only relevant if {@link OpenSeadragon.Options}.loadTilesWithAjax is set to true. + * @function + * @param {Number} level + * @param {Number} x + * @param {Number} y + * @returns {Object} + */ + getTileHeaders: function( level, x, y ) { + return {}; + }, + /** * @function * @param {Number} level diff --git a/src/viewer.js b/src/viewer.js index ec4c8242..6117d572 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -1232,6 +1232,14 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, * @param {String} [options.compositeOperation] How the image is composited onto other images. * @param {String} [options.crossOriginPolicy] The crossOriginPolicy for this specific image, * overriding viewer.crossOriginPolicy. + * @param {Boolean} [options.ajaxWithCredentials] Whether to set withCredentials on tile AJAX + * @param {Boolean} [options.loadTilesWithAjax] + * Whether to load tile data using AJAX requests. + * Defaults to the setting in {@link OpenSeadragon.Options}. + * @param {Object} [options.ajaxRequestHeaders] + * 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}. + * 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", the resulting TiledImage. @@ -1270,6 +1278,21 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, if (options.crossOriginPolicy === undefined) { options.crossOriginPolicy = options.tileSource.crossOriginPolicy !== undefined ? options.tileSource.crossOriginPolicy : this.crossOriginPolicy; } + if (options.ajaxWithCredentials === undefined) { + options.ajaxWithCredentials = this.ajaxWithCredentials; + } + if (options.loadTilesWithAjax === undefined) { + options.loadTilesWithAjax = this.loadTilesWithAjax; + } + if (options.ajaxRequestHeaders === undefined) { + options.ajaxRequestHeaders = this.ajaxRequestHeaders; + } else if ( + $.isPlainObject(options.ajaxRequestHeaders) && + $.isPlainObject(this.ajaxRequestHeaders) + ) { + options.ajaxRequestHeaders = $.extend({}, + this.ajaxRequestHeaders, options.ajaxRequestHeaders); + } var myQueueItem = { options: options @@ -1384,6 +1407,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, smoothTileEdgesMinZoom: _this.smoothTileEdgesMinZoom, iOSDevice: _this.iOSDevice, crossOriginPolicy: queueItem.options.crossOriginPolicy, + ajaxWithCredentials: queueItem.options.ajaxWithCredentials, + loadTilesWithAjax: queueItem.options.loadTilesWithAjax, + ajaxRequestHeaders: queueItem.options.ajaxRequestHeaders, debugMode: _this.debugMode }); @@ -2156,6 +2182,7 @@ function getTileSourceImplementation( viewer, tileSource, imgOptions, successCal crossOriginPolicy: imgOptions.crossOriginPolicy !== undefined ? imgOptions.crossOriginPolicy : viewer.crossOriginPolicy, ajaxWithCredentials: viewer.ajaxWithCredentials, + ajaxRequestHeaders: viewer.ajaxRequestHeaders, useCanvas: viewer.useCanvas, success: function( event ) { successCallback( event.tileSource ); diff --git a/test/data/testpattern.blob b/test/data/testpattern.blob new file mode 100644 index 00000000..fe027d91 Binary files /dev/null and b/test/data/testpattern.blob differ diff --git a/test/demo/basic.html b/test/demo/basic.html index e238e5e1..2b9481e7 100644 --- a/test/demo/basic.html +++ b/test/demo/basic.html @@ -25,7 +25,8 @@ id: "contentDiv", prefixUrl: "../../build/openseadragon/images/", tileSources: "../data/testpattern.dzi", - showNavigator:true + showNavigator:true, + ajaxWithCredentials: true }); diff --git a/test/demo/customheaders.html b/test/demo/customheaders.html new file mode 100644 index 00000000..bc43263a --- /dev/null +++ b/test/demo/customheaders.html @@ -0,0 +1,76 @@ + + + + OpenSeadragon Custom Request Headers Demo + + + + + +

+ Demo of how the loadTilesWithAjax and ajaxRequestHeaders options as well as the getTileHeaders() method on TileSource can be applied. +

+

+ Examine the network requests in your browser developer tools to see the custom headers sent with each request. +

+
+ + + diff --git a/test/modules/tilecache.js b/test/modules/tilecache.js index 80bb44de..ba89b73a 100644 --- a/test/modules/tilecache.js +++ b/test/modules/tilecache.js @@ -25,12 +25,14 @@ var fakeTile0 = { url: 'foo.jpg', + cacheKey: 'foo.jpg', image: {}, unload: function() {} }; var fakeTile1 = { url: 'foo.jpg', + cacheKey: 'foo.jpg', image: {}, unload: function() {} }; @@ -74,18 +76,21 @@ var fakeTile0 = { url: 'different.jpg', + cacheKey: 'different.jpg', image: {}, unload: function() {} }; var fakeTile1 = { url: 'same.jpg', + cacheKey: 'same.jpg', image: {}, unload: function() {} }; var fakeTile2 = { url: 'same.jpg', + cacheKey: 'same.jpg', image: {}, unload: function() {} };