Merge pull request #553 from openseadragon/ajax

Allowing XHRs withCredentials for authenticated requests
This commit is contained in:
Ian Gilman 2015-01-15 14:35:06 -08:00
commit c55daff222
4 changed files with 133 additions and 78 deletions

View File

@ -39,6 +39,7 @@ OPENSEADRAGON CHANGELOG
* Rect and Point toString() functions are now consistent: rounding values to nearest hundredth * Rect and Point toString() functions are now consistent: rounding values to nearest hundredth
* Overlays appear in the DOM immediately on open or addOverlay (#507) * Overlays appear in the DOM immediately on open or addOverlay (#507)
* imageLoaderLimit now works (#544) * imageLoaderLimit now works (#544)
* Added ajaxWithCredentials option (#543)
1.2.1: (in progress) 1.2.1: (in progress)

View File

@ -562,6 +562,10 @@
* Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will * Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will
* not use CORS, and the canvas will be tainted. * 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).
* Note that this can be overridden at the {@link OpenSeadragon.TileSource} level.
*
*/ */
/** /**
@ -919,6 +923,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
tileHost: null, tileHost: null,
initialPage: 0, initialPage: 0,
crossOriginPolicy: false, crossOriginPolicy: false,
ajaxWithCredentials: false,
//PAN AND ZOOM SETTINGS AND CONSTRAINTS //PAN AND ZOOM SETTINGS AND CONSTRAINTS
panHorizontal: true, panHorizontal: true,
@ -1925,13 +1930,25 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
/** /**
* Makes an AJAX request. * Makes an AJAX request.
* @function * @param {Object} options
* @param {String} url - the url to request * @param {String} options.url - the url to request
* @param {Function} onSuccess - a function to call on a successful response * @param {Function} options.success - a function to call on a successful response
* @param {Function} onError - a function to call on when an error occurs * @param {Function} options.error - a function to call on when an error occurs
* @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials
* @throws {Error} * @throws {Error}
*/ */
makeAjaxRequest: function( url, onSuccess, onError ) { makeAjaxRequest: function( url, onSuccess, onError ) {
var withCredentials;
// Note that our preferred API is that you pass in a single object; the named
// arguments are for legacy support.
if( $.isPlainObject( url ) ){
onSuccess = url.success;
onError = url.error;
withCredentials = url.withCredentials;
url = url.url;
}
var protocol = $.getUrlProtocol( url ); var protocol = $.getUrlProtocol( url );
var request = $.createAjaxRequest( protocol === "file:" ); var request = $.createAjaxRequest( protocol === "file:" );
@ -1958,6 +1975,10 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
} }
}; };
if (withCredentials) {
request.withCredentials = true;
}
try { try {
request.open( "GET", url, true ); request.open( "GET", url, true );
request.send( null ); request.send( null );

View File

@ -38,44 +38,52 @@
/** /**
* @class TileSource * @class TileSource
* @classdesc The TileSource contains the most basic implementation required to create a * @classdesc The TileSource contains the most basic implementation required to create a
* smooth transition between layer in an image pyramid. It has only a single key * smooth transition between layers in an image pyramid. It has only a single key
* interface that must be implemented to complete it key functionality: * interface that must be implemented to complete its key functionality:
* 'getTileUrl'. It also has several optional interfaces that can be * 'getTileUrl'. It also has several optional interfaces that can be
* implemented if a new TileSource wishes to support configuration via a simple * implemented if a new TileSource wishes to support configuration via a simple
* object or array ('configure') and if the tile source supports or requires * object or array ('configure') and if the tile source supports or requires
* configuration via retreival of a document on the network ala AJAX or JSONP, * configuration via retrieval of a document on the network ala AJAX or JSONP,
* ('getImageInfo'). * ('getImageInfo').
* <br/> * <br/>
* By default the image pyramid is split into N layers where the images longest * By default the image pyramid is split into N layers where the image's longest
* side in M (in pixels), where N is the smallest integer which satisfies * side in M (in pixels), where N is the smallest integer which satisfies
* <strong>2^(N+1) >= M</strong>. * <strong>2^(N+1) >= M</strong>.
* *
* @memberof OpenSeadragon * @memberof OpenSeadragon
* @extends OpenSeadragon.EventSource * @extends OpenSeadragon.EventSource
* @param {Number|Object|Array|String} width * @param {Object} options
* If more than a single argument is supplied, the traditional use of * You can either specify a URL, or literally define the TileSource (by specifying
* positional parameters is supplied and width is expected to be the width * width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former,
* source image at its max resolution in pixels. If a single argument is supplied and * the extending class is expected to implement 'getImageInfo' and 'configure'.
* it is an Object or Array, the construction is assumed to occur through * For the latter, the construction is assumed to occur through
* the extending classes implementation of 'configure'. Finally if only a * the extending classes implementation of 'configure'.
* single argument is supplied and it is a String, the extending class is * @param {String} [options.url]
* expected to implement 'getImageInfo' and 'configure'. * The URL for the data necessary for this TileSource.
* @param {Number} height * @param {Function} [options.success]
* A function to be called upon successful creation.
* @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 {Number} [options.width]
* Width of the source image at max resolution in pixels. * Width of the source image at max resolution in pixels.
* @param {Number} tileSize * @param {Number} [options.height]
* Height of the source image at max resolution in pixels.
* @param {Number} [options.tileSize]
* The size of the tiles to assumed to make up each pyramid layer in pixels. * The size of the tiles to assumed to make up each pyramid layer in pixels.
* Tile size determines the point at which the image pyramid must be * Tile size determines the point at which the image pyramid must be
* divided into a matrix of smaller images. * divided into a matrix of smaller images.
* @param {Number} tileOverlap * @param {Number} [options.tileOverlap]
* The number of pixels each tile is expected to overlap touching tiles. * The number of pixels each tile is expected to overlap touching tiles.
* @param {Number} minLevel * @param {Number} [options.minLevel]
* The minimum level to attempt to load. * The minimum level to attempt to load.
* @param {Number} maxLevel * @param {Number} [options.maxLevel]
* The maximum level to attempt to load. * The maximum level to attempt to load.
*/ */
$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) { $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) {
var callback = null, var _this = this;
args = arguments,
var args = arguments,
options, options,
i; i;
@ -102,18 +110,22 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
//source //source
$.extend( true, this, options ); $.extend( true, this, options );
if (!this.success) {
//Any functions that are passed as arguments are bound to the ready callback //Any functions that are passed as arguments are bound to the ready callback
/*jshint loopfunc:true*/
for ( i = 0; i < arguments.length; i++ ) { for ( i = 0; i < arguments.length; i++ ) {
if ( $.isFunction( arguments[ i ] ) ) { if ( $.isFunction( arguments[ i ] ) ) {
callback = arguments[ i ]; this.success = arguments[ i ];
this.addHandler( 'ready', function ( event ) {
callback( event );
} );
//only one callback per constructor //only one callback per constructor
break; break;
} }
} }
}
if (this.success) {
this.addHandler( 'ready', function ( event ) {
_this.success( event );
} );
}
/** /**
* Ratio of width to height * Ratio of width to height
@ -154,6 +166,10 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
*/ */
if( 'string' == $.type( arguments[ 0 ] ) ){ if( 'string' == $.type( arguments[ 0 ] ) ){
this.url = arguments[0];
}
if (this.url) {
//in case the getImageInfo method is overriden and/or implies an //in case the getImageInfo method is overriden and/or implies an
//async mechanism set some safe defaults first //async mechanism set some safe defaults first
this.aspectRatio = 1; this.aspectRatio = 1;
@ -165,7 +181,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
this.ready = false; this.ready = false;
//configuration via url implies the extending class //configuration via url implies the extending class
//implements and 'configure' //implements and 'configure'
this.getImageInfo( arguments[ 0 ] ); this.getImageInfo( this.url );
} else { } else {
@ -185,8 +201,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
Math.log( 2 ) Math.log( 2 )
) : 0 ) : 0
); );
if( callback && $.isFunction( callback ) ){ if( this.success && $.isFunction( this.success ) ){
callback( this ); this.success( this );
} }
} }
@ -355,6 +371,10 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
} }
options = $TileSource.prototype.configure.apply( _this, [ data, url ]); options = $TileSource.prototype.configure.apply( _this, [ data, url ]);
if (options.ajaxWithCredentials === undefined) {
options.ajaxWithCredentials = _this.ajaxWithCredentials;
}
readySource = new $TileSource( options ); readySource = new $TileSource( options );
_this.ready = true; _this.ready = true;
/** /**
@ -383,10 +403,14 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
}); });
} else { } else {
// request info via xhr asynchronously. // request info via xhr asynchronously.
$.makeAjaxRequest( url, function( xhr ) { $.makeAjaxRequest( {
url: url,
withCredentials: this.ajaxWithCredentials,
success: function( xhr ) {
var data = processResponse( xhr ); var data = processResponse( xhr );
callback( data ); callback( data );
}, function ( xhr, exc ) { },
error: function ( xhr, exc ) {
var msg; var msg;
/* /*
@ -422,6 +446,7 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
message: msg, message: msg,
source: url source: url
}); });
}
}); });
} }

View File

@ -2058,14 +2058,22 @@ function getTileSourceImplementation( viewer, tileSource, successCallback,
setTimeout( function() { setTimeout( function() {
if ( $.type( tileSource ) == 'string' ) { if ( $.type( tileSource ) == 'string' ) {
//If its still a string it means it must be a url at this point //If its still a string it means it must be a url at this point
tileSource = new $.TileSource( tileSource, function( event ) { tileSource = new $.TileSource({
url: tileSource,
ajaxWithCredentials: viewer.ajaxWithCredentials,
success: function( event ) {
successCallback( event.tileSource ); successCallback( event.tileSource );
}
}); });
tileSource.addHandler( 'open-failed', function( event ) { tileSource.addHandler( 'open-failed', function( event ) {
failCallback( event ); failCallback( event );
} ); } );
} else if ( $.isPlainObject( tileSource ) || tileSource.nodeType ) { } else if ( $.isPlainObject( tileSource ) || tileSource.nodeType ) {
if (tileSource.ajaxWithCredentials === undefined) {
tileSource.ajaxWithCredentials = viewer.ajaxWithCredentials;
}
if ( $.isFunction( tileSource.getTileUrl ) ) { if ( $.isFunction( tileSource.getTileUrl ) ) {
//Custom tile source //Custom tile source
var customTileSource = new $.TileSource( tileSource ); var customTileSource = new $.TileSource( tileSource );