From 1c14f5cc9430b060a152a92a40e2c43b938e7dd9 Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Mon, 22 Jun 2015 13:26:24 -0600
Subject: [PATCH 01/16] Added code to handle the case where autoResize=false.
 In this mode the image size is preserved and the center is maintained. This
 may be considered changing the default behavior so I'd welcome a suggestion
 to add a configuration parameter to help preserve the default behavior.

---
 src/viewer.js | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/viewer.js b/src/viewer.js
index 7143443d..26ac3aa2 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2835,6 +2835,28 @@ function updateOnce( viewer ) {
             THIS[ viewer.hash ].forceRedraw = true;
         }
     }
+    else {
+        var containerSize = _getSafeElemSize( viewer.container );
+        if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
+            var prevContainerSize = THIS[ viewer.hash ].prevContainerSize;
+            var bounds = viewer.viewport.getBounds(true);
+            var deltaX = (containerSize.x - prevContainerSize.x);
+            var deltaY = (containerSize.y - prevContainerSize.y);
+            var viewportDiff = viewer.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(deltaX, deltaY), true);
+            viewer.viewport.resize(new OpenSeadragon.Point(containerSize.x, containerSize.y), false);
+
+            // Keep the center of the image in the center and just adjust the amount of image shown
+            bounds.width += viewportDiff.x;
+            bounds.height += viewportDiff.y;
+            bounds.x -= (viewportDiff.x / 2);
+            bounds.y -= (viewportDiff.y / 2);
+            viewer.viewport.fitBounds(bounds, true);
+            viewer.forceRedraw();
+
+            THIS[ viewer.hash ].prevContainerSize = containerSize;
+            THIS[ viewer.hash ].forceRedraw = true;
+        }
+    }
 
     var viewportChange = viewer.viewport.update();
     var animated = viewer.world.update() || viewportChange;

From 57c06a9a199ae85b5dd3a8275bc133339297ce08 Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Mon, 22 Jun 2015 13:35:45 -0600
Subject: [PATCH 02/16] Fixed problem with build complaining about variable
 name reuse.

---
 src/viewer.js | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/viewer.js b/src/viewer.js
index 26ac3aa2..efe1ea36 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2824,8 +2824,9 @@ function updateOnce( viewer ) {
         return;
     }
 
+    var containerSize;
     if ( viewer.autoResize ) {
-        var containerSize = _getSafeElemSize( viewer.container );
+        containerSize = _getSafeElemSize( viewer.container );
         if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
             // maintain image position
             var oldBounds = viewer.viewport.getBounds();
@@ -2836,7 +2837,7 @@ function updateOnce( viewer ) {
         }
     }
     else {
-        var containerSize = _getSafeElemSize( viewer.container );
+        containerSize = _getSafeElemSize( viewer.container );
         if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
             var prevContainerSize = THIS[ viewer.hash ].prevContainerSize;
             var bounds = viewer.viewport.getBounds(true);

From fb21dabd7687c4d0ba80252025328e0644d04cec Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Tue, 23 Jun 2015 10:55:57 -0600
Subject: [PATCH 03/16] Added configuration parameter:
 preserveImageSizeOnResize to preserve the default behavior. Changed fitBounds
 to fitBoundsWithConstraints as per Ian's instructions.

---
 src/openseadragon.js | 4 ++++
 src/viewer.js        | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/openseadragon.js b/src/openseadragon.js
index 461f9d22..0c6df401 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -252,6 +252,9 @@
   * @property {Boolean} [autoResize=true]
   *     Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior.
   *
+  * @property {Boolean} [preserveImageSizeOnResize=false]
+  *     Set to true to have the image size preserved when the viewer is resized. This requires autoResize=false.
+  *
   * @property {Number} [pixelsPerWheelLine=40]
   *     For pixel-resolution scrolling devices, the number of pixels equal to one scroll line.
   *
@@ -987,6 +990,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
             maxZoomPixelRatio:      1.1, //-> higher allows 'over zoom' into pixels
             pixelsPerWheelLine:     40,
             autoResize:             true,
+            preserveImageSizeOnResize: false, // requires autoResize=false
 
             //DEFAULT CONTROL SETTINGS
             showSequenceControl:     true,  //SEQUENCE
diff --git a/src/viewer.js b/src/viewer.js
index efe1ea36..50dd8831 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -408,6 +408,7 @@ $.Viewer = function( options ) {
             width:             this.navigatorWidth,
             height:            this.navigatorHeight,
             autoResize:        this.navigatorAutoResize,
+            preserveImageSizeOnResize: this.preserveImageSizeOnResize,
             prefixUrl:         this.prefixUrl,
             viewer:            this,
             navigatorRotate:   this.navigatorRotate,
@@ -2836,7 +2837,7 @@ function updateOnce( viewer ) {
             THIS[ viewer.hash ].forceRedraw = true;
         }
     }
-    else {
+    else if ( viewer.preserveImageSizeOnResize ) {
         containerSize = _getSafeElemSize( viewer.container );
         if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
             var prevContainerSize = THIS[ viewer.hash ].prevContainerSize;
@@ -2851,7 +2852,7 @@ function updateOnce( viewer ) {
             bounds.height += viewportDiff.y;
             bounds.x -= (viewportDiff.x / 2);
             bounds.y -= (viewportDiff.y / 2);
-            viewer.viewport.fitBounds(bounds, true);
+            viewer.viewport.fitBoundsWithConstraints(bounds, true);
             viewer.forceRedraw();
 
             THIS[ viewer.hash ].prevContainerSize = containerSize;

From df878f6f82a77081671eeab50aca9e23437d6e85 Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Wed, 24 Jun 2015 10:48:00 -0600
Subject: [PATCH 04/16] Changed preserveImageSizeOnResize to require
 autoResize=true. Refactored resizing code to share more code. Removed
 preserveImageSizeOnResize parameter from viewer.

---
 src/openseadragon.js |  2 +-
 src/viewer.js        | 46 +++++++++++++++++++-------------------------
 2 files changed, 21 insertions(+), 27 deletions(-)

diff --git a/src/openseadragon.js b/src/openseadragon.js
index 0c6df401..b7f7f5c1 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -253,7 +253,7 @@
   *     Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior.
   *
   * @property {Boolean} [preserveImageSizeOnResize=false]
-  *     Set to true to have the image size preserved when the viewer is resized. This requires autoResize=false.
+  *     Set to true to have the image size preserved when the viewer is resized. This requires autoResize=true (default).
   *
   * @property {Number} [pixelsPerWheelLine=40]
   *     For pixel-resolution scrolling devices, the number of pixels equal to one scroll line.
diff --git a/src/viewer.js b/src/viewer.js
index 50dd8831..3e318528 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -408,7 +408,6 @@ $.Viewer = function( options ) {
             width:             this.navigatorWidth,
             height:            this.navigatorHeight,
             autoResize:        this.navigatorAutoResize,
-            preserveImageSizeOnResize: this.preserveImageSizeOnResize,
             prefixUrl:         this.prefixUrl,
             viewer:            this,
             navigatorRotate:   this.navigatorRotate,
@@ -2829,32 +2828,27 @@ function updateOnce( viewer ) {
     if ( viewer.autoResize ) {
         containerSize = _getSafeElemSize( viewer.container );
         if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
-            // maintain image position
-            var oldBounds = viewer.viewport.getBounds();
-            var oldCenter = viewer.viewport.getCenter();
-            resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter);
-            THIS[ viewer.hash ].prevContainerSize = containerSize;
-            THIS[ viewer.hash ].forceRedraw = true;
-        }
-    }
-    else if ( viewer.preserveImageSizeOnResize ) {
-        containerSize = _getSafeElemSize( viewer.container );
-        if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
-            var prevContainerSize = THIS[ viewer.hash ].prevContainerSize;
-            var bounds = viewer.viewport.getBounds(true);
-            var deltaX = (containerSize.x - prevContainerSize.x);
-            var deltaY = (containerSize.y - prevContainerSize.y);
-            var viewportDiff = viewer.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(deltaX, deltaY), true);
-            viewer.viewport.resize(new OpenSeadragon.Point(containerSize.x, containerSize.y), false);
-
-            // Keep the center of the image in the center and just adjust the amount of image shown
-            bounds.width += viewportDiff.x;
-            bounds.height += viewportDiff.y;
-            bounds.x -= (viewportDiff.x / 2);
-            bounds.y -= (viewportDiff.y / 2);
-            viewer.viewport.fitBoundsWithConstraints(bounds, true);
-            viewer.forceRedraw();
+            if ( viewer.preserveImageSizeOnResize ) {
+                var prevContainerSize = THIS[ viewer.hash ].prevContainerSize;
+                var bounds = viewer.viewport.getBounds(true);
+                var deltaX = (containerSize.x - prevContainerSize.x);
+                var deltaY = (containerSize.y - prevContainerSize.y);
+                var viewportDiff = viewer.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(deltaX, deltaY), true);
+                viewer.viewport.resize(new OpenSeadragon.Point(containerSize.x, containerSize.y), false);
 
+                // Keep the center of the image in the center and just adjust the amount of image shown
+                bounds.width += viewportDiff.x;
+                bounds.height += viewportDiff.y;
+                bounds.x -= (viewportDiff.x / 2);
+                bounds.y -= (viewportDiff.y / 2);
+                viewer.viewport.fitBoundsWithConstraints(bounds, true);
+            }
+            else {
+                // maintain image position
+                var oldBounds = viewer.viewport.getBounds();
+                var oldCenter = viewer.viewport.getCenter();
+                resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter);
+            }
             THIS[ viewer.hash ].prevContainerSize = containerSize;
             THIS[ viewer.hash ].forceRedraw = true;
         }

From 0806e4d4ed445fbef748c68b62bf9c678e46a4b1 Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Thu, 25 Jun 2015 14:14:05 -0600
Subject: [PATCH 05/16] Fixed comment regarding autoResize.

---
 src/openseadragon.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/openseadragon.js b/src/openseadragon.js
index b7f7f5c1..e20926bd 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -990,7 +990,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
             maxZoomPixelRatio:      1.1, //-> higher allows 'over zoom' into pixels
             pixelsPerWheelLine:     40,
             autoResize:             true,
-            preserveImageSizeOnResize: false, // requires autoResize=false
+            preserveImageSizeOnResize: false, // requires autoResize=true
 
             //DEFAULT CONTROL SETTINGS
             showSequenceControl:     true,  //SEQUENCE

From b09897dbf1352d91439b5e65c8e0276ed44eff4e Mon Sep 17 00:00:00 2001
From: Ian Gilman <ian@iangilman.com>
Date: Mon, 29 Jun 2015 14:16:11 -0700
Subject: [PATCH 06/16] Added changelog for #666

---
 changelog.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/changelog.txt b/changelog.txt
index d62a3a33..e42893fb 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -9,6 +9,7 @@ OPENSEADRAGON CHANGELOG
 * Fixed flickering tiles with useCanvas=false when no cache is used (#661)
 * Added additional coordinates conversion methods to TiledImage (#662)
 * 'display: none' no longer gets reset on overlays during draw (#668)
+* Added `preserveImageSizeOnResize` option (#666)
 
 2.0.0:
 

From c25f3e374b1298825a9515859dc0d8114729c68f Mon Sep 17 00:00:00 2001
From: Ian Gilman <ian@iangilman.com>
Date: Mon, 29 Jun 2015 14:21:53 -0700
Subject: [PATCH 07/16] Newer versions of qunit and qunit-istanbul

---
 package.json | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/package.json b/package.json
index c979f4b8..d2081b58 100644
--- a/package.json
+++ b/package.json
@@ -5,16 +5,16 @@
   "devDependencies": {
     "grunt": "^0.4.5",
     "grunt-contrib-clean": "^0.5.0",
-    "grunt-text-replace": "^0.3.11",
+    "grunt-contrib-compress": "^0.9.1",
     "grunt-contrib-concat": "^0.4.0",
-    "grunt-git-describe": "^2.3.2",
+    "grunt-contrib-connect": "^0.7.1",
+    "grunt-contrib-jshint": "^0.10.0",
     "grunt-contrib-uglify": "^0.4.0",
     "grunt-contrib-watch": "^0.6.1",
-    "grunt-contrib-jshint": "^0.10.0",
-    "grunt-contrib-compress": "^0.9.1",
-    "grunt-contrib-connect": "^0.7.1",
-    "qunitjs": "^1.14.0",
-    "grunt-qunit-istanbul": "^0.4.5"
+    "grunt-git-describe": "^2.3.2",
+    "grunt-qunit-istanbul": "^0.5.0",
+    "grunt-text-replace": "^0.3.11",
+    "qunitjs": "^1.18.0"
   },
   "scripts": {
     "test": "grunt test"

From 6db00ad2865c6ac5c115ff9b57645e83c07b3030 Mon Sep 17 00:00:00 2001
From: Ian Gilman <ian@iangilman.com>
Date: Tue, 30 Jun 2015 10:58:51 -0700
Subject: [PATCH 08/16] Overlay doc fixes

---
 src/viewer.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/viewer.js b/src/viewer.js
index 3e318528..f93c8e23 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -1710,7 +1710,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * is closed which include when changing page.
      * @method
      * @param {Element|String|Object} element - A reference to an element or an id for
-     *      the element which will overlayed. Or an Object specifying the configuration for the overlay
+     *      the element which will be overlayed. Or an Object specifying the configuration for the overlay
      * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
      *      rectangle which will be overlayed.
      * @param {OpenSeadragon.OverlayPlacement} placement - The position of the
@@ -1770,6 +1770,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * Updates the overlay represented by the reference to the element or
      * element id moving it to the new location, relative to the new placement.
      * @method
+     * @param {Element|String} element - A reference to an element or an id for
+     *      the element which is overlayed.
      * @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
      *      rectangle which will be overlayed.
      * @param {OpenSeadragon.OverlayPlacement} placement - The position of the

From 339401683f50dc679fa0d0e9be87b3510ed8290c Mon Sep 17 00:00:00 2001
From: Larissa Smith <smithl@familysearch.org>
Date: Thu, 2 Jul 2015 13:20:57 -0600
Subject: [PATCH 09/16] Added configuration parameter to allow a horizontal
 layout that has a fixed number of columns or a vertical layout that has a
 fixed number of rows.

---
 src/openseadragon.js | 5 +++++
 src/viewer.js        | 1 +
 src/world.js         | 9 ++++++++-
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/openseadragon.js b/src/openseadragon.js
index e20926bd..64349972 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -559,6 +559,10 @@
   *     If collectionMode is true, specifies how many rows the grid should have. Use 1 to make a line.
   *     If collectionLayout is 'vertical', specifies how many columns instead.
   *
+  * @property {Number} [collectionColumns=0]
+  *     If collectionMode is true, specifies how many columns the grid should have. Use 1 to make a line.
+  *     If collectionLayout is 'vertical', specifies how many rows instead. Ignored if collectionRows is not set to a falsy value.
+  *
   * @property {String} [collectionLayout='horizontal']
   *     If collectionMode is true, specifies whether to arrange vertically or horizontally.
   *
@@ -1039,6 +1043,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
 
             //COLLECTION VISUALIZATION SETTINGS
             collectionRows:         3, //or columns depending on layout
+            collectionColumns:      0, //columns in horizontal layout, rows in vertical layout
             collectionLayout:       'horizontal', //vertical
             collectionMode:         false,
             collectionTileSize:     800,
diff --git a/src/viewer.js b/src/viewer.js
index f93c8e23..01560f01 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -1318,6 +1318,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
                     _this.world.arrange({
                         immediately: queueItem.options.collectionImmediately,
                         rows: _this.collectionRows,
+                        columns: _this.collectionColumns,
                         layout: _this.collectionLayout,
                         tileSize: _this.collectionTileSize,
                         tileMargin: _this.collectionTileMargin
diff --git a/src/world.js b/src/world.js
index c9e65225..73b28a67 100644
--- a/src/world.js
+++ b/src/world.js
@@ -281,6 +281,7 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
      * @param {Boolean} [options.immediately=false] - Whether to animate to the new arrangement.
      * @param {String} [options.layout] - See collectionLayout in {@link OpenSeadragon.Options}.
      * @param {Number} [options.rows] - See collectionRows in {@link OpenSeadragon.Options}.
+     * @param {Number} [options.columns] - See collectionColumns in {@link OpenSeadragon.Options}.
      * @param {Number} [options.tileSize] - See collectionTileSize in {@link OpenSeadragon.Options}.
      * @param {Number} [options.tileMargin] - See collectionTileMargin in {@link OpenSeadragon.Options}.
      * @fires OpenSeadragon.World.event:metrics-change
@@ -290,10 +291,16 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
         var immediately = options.immediately || false;
         var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout;
         var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows;
+        var columns = options.columns || $.DEFAULT_SETTINGS.collectionColumns;
         var tileSize = options.tileSize || $.DEFAULT_SETTINGS.collectionTileSize;
         var tileMargin = options.tileMargin || $.DEFAULT_SETTINGS.collectionTileMargin;
         var increment = tileSize + tileMargin;
-        var wrap = Math.ceil(this._items.length / rows);
+        var wrap;
+        if (!options.rows && columns) {
+            wrap = columns;
+        } else {
+            wrap = Math.ceil(this._items.length / rows);
+        }
         var x = 0;
         var y = 0;
         var item, box, width, height, position;

From e93a0862bd442a1a923383cd7ff667487f0d2bd8 Mon Sep 17 00:00:00 2001
From: Ian Gilman <ian@iangilman.com>
Date: Fri, 3 Jul 2015 10:19:10 -0700
Subject: [PATCH 10/16] Added demo for TileSource swapping

---
 test/demo/tilesource-swap.html | 96 ++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 test/demo/tilesource-swap.html

diff --git a/test/demo/tilesource-swap.html b/test/demo/tilesource-swap.html
new file mode 100644
index 00000000..3420927c
--- /dev/null
+++ b/test/demo/tilesource-swap.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>TileSource Swapping</title>
+        <script type="text/javascript" src="../../build/openseadragon/openseadragon.js"></script>
+        <script type="text/javascript" src="../lib/jquery-1.9.1.min.js"></script>
+        <style type="text/css">
+
+            html,
+            body {
+                width: 100%;
+                height: 100%;
+                margin: 0;
+            }
+
+            .viewer-position {
+                position: absolute;
+                left: 0;
+                top: 30px;
+                right: 0;
+                bottom: 0;
+            }
+
+        </style>
+    </head>
+    <body>
+        <div>This is a demo of using a single image stand-in and then swapping to a full TileSource on zooming. Click the image to see it in action.</div>
+        <div id="openseadragon1" class="viewer-position"></div>
+        <script>
+
+            var duomoStandin = {
+                type: 'legacy-image-pyramid',
+                levels: [
+                    {
+                        url: 'http://openseadragon.github.io/example-images/duomo/duomo_files/8/0_0.jpg',
+                        width: 218,
+                        height: 160
+                    }
+                ]
+            };
+
+            var duomo = {
+                Image: {
+                    xmlns: 'http://schemas.microsoft.com/deepzoom/2008',
+                    Url: 'http://openseadragon.github.io/example-images/duomo/duomo_files/',
+                    Format: 'jpg',
+                    Overlap: '2',
+                    TileSize: '256',
+                    Size: {
+                        Width:  '13920',
+                        Height: '10200'
+                    }
+                }
+            };
+
+            var viewer = OpenSeadragon({
+                id: 'openseadragon1',
+                prefixUrl: '../../build/openseadragon/images/',
+                tileSources: duomoStandin,
+                minZoomImageRatio: 0.1,
+                defaultZoomLevel: 0.1,
+                zoomPerClick: 1
+            });
+
+            viewer.addHandler('canvas-click', function(event) {
+                if (event.quick) {
+                    var standin = viewer.world.getItemAt(0);
+                    var standinBounds = standin.getBounds();
+                    viewer.viewport.fitBounds(standinBounds);
+
+                    viewer.addTiledImage({
+                        x: standinBounds.x,
+                        y: standinBounds.y,
+                        width: standinBounds.width,
+                        tileSource: duomo,
+                        index: 0, // Add the new image below the stand-in.
+                        success: function(event) {
+                            var fullImage = event.item;
+
+                            // The changeover will look better if we wait for the first tile to be drawn.
+                            var tileDrawnHandler = function(event) {
+                                if (event.tiledImage === fullImage) {
+                                    viewer.removeHandler('tile-drawn', tileDrawnHandler);
+                                    viewer.world.removeItem(standin);
+                                }
+                            };
+
+                            viewer.addHandler('tile-drawn', tileDrawnHandler);
+                        }
+                    });
+                }
+            });
+
+        </script>
+    </body>
+</html>

From 8b71876c37d99953475d64cf12c972c4d8d7182a Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Mon, 6 Jul 2015 14:56:41 -0600
Subject: [PATCH 11/16] Added error message tracking into the tile loading
 mechanism. This exposes the reason for the error in the console.log message

---
 src/imageloader.js | 5 ++++-
 src/tiledimage.js  | 8 ++++----
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/imageloader.js b/src/imageloader.js
index a61c8936..ef3a4f4f 100644
--- a/src/imageloader.js
+++ b/src/imageloader.js
@@ -51,6 +51,7 @@ function ImageJob ( options ) {
 }
 
 ImageJob.prototype = {
+    errorMsg: null,
     start: function(){
         var _this = this;
 
@@ -64,10 +65,12 @@ ImageJob.prototype = {
             _this.finish( true );
         };
         this.image.onabort = this.image.onerror = function(){
+            _this.errorMsg = "Image load aborted";
             _this.finish( false );
         };
 
         this.jobId = window.setTimeout( function(){
+            _this.errorMsg = "Image load exceeded timeout";
             _this.finish( false );
         }, this.timeout);
 
@@ -173,7 +176,7 @@ function completeJob( loader, job, callback ) {
         loader.jobsInProgress++;
     }
 
-    callback( job.image );
+    callback( job.image, job.errorMsg );
 }
 
 }( OpenSeadragon ));
diff --git a/src/tiledimage.js b/src/tiledimage.js
index 363df7c6..f4f9ee3f 100644
--- a/src/tiledimage.js
+++ b/src/tiledimage.js
@@ -1011,8 +1011,8 @@ function loadTile( tiledImage, tile, time ) {
     tiledImage._imageLoader.addJob({
         src: tile.url,
         crossOriginPolicy: tiledImage.crossOriginPolicy,
-        callback: function( image ){
-            onTileLoad( tiledImage, tile, time, image );
+        callback: function( image, errorMsg ){
+            onTileLoad( tiledImage, tile, time, image, errorMsg );
         },
         abort: function() {
             tile.loading = false;
@@ -1020,9 +1020,9 @@ function loadTile( tiledImage, tile, time ) {
     });
 }
 
-function onTileLoad( tiledImage, tile, time, image ) {
+function onTileLoad( tiledImage, tile, time, image, errorMsg ) {
     if ( !image ) {
-        $.console.log( "Tile %s failed to load: %s", tile, tile.url );
+        $.console.log( "Tile %s failed to load: %s", tile.url, errorMsg );
         if( !tiledImage.debugMode ){
             tile.loading = false;
             tile.exists = false;

From 9629f47c2c1adbcf7d59d5872e2d8a32b9578b2d Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Mon, 6 Jul 2015 15:06:00 -0600
Subject: [PATCH 12/16] Added error message tracking into the tile loading
 mechanism. This exposes the reason for the error in the console.log message

---
 src/tiledimage.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tiledimage.js b/src/tiledimage.js
index f4f9ee3f..43285d4d 100644
--- a/src/tiledimage.js
+++ b/src/tiledimage.js
@@ -1022,7 +1022,7 @@ function loadTile( tiledImage, tile, time ) {
 
 function onTileLoad( tiledImage, tile, time, image, errorMsg ) {
     if ( !image ) {
-        $.console.log( "Tile %s failed to load: %s", tile.url, errorMsg );
+        $.console.log( "Tile %s failed to load: %s - error:", tile, tile.url, errorMsg );
         if( !tiledImage.debugMode ){
             tile.loading = false;
             tile.exists = false;

From 553948781486bed2e2a6cef046e56be78f4855fc Mon Sep 17 00:00:00 2001
From: Grant Echols <gechols@ldschurch.org>
Date: Mon, 6 Jul 2015 15:07:00 -0600
Subject: [PATCH 13/16] Added error message tracking into the tile loading
 mechanism. This exposes the reason for the error in the console.log message

---
 src/tiledimage.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tiledimage.js b/src/tiledimage.js
index 43285d4d..960d91d9 100644
--- a/src/tiledimage.js
+++ b/src/tiledimage.js
@@ -1022,7 +1022,7 @@ function loadTile( tiledImage, tile, time ) {
 
 function onTileLoad( tiledImage, tile, time, image, errorMsg ) {
     if ( !image ) {
-        $.console.log( "Tile %s failed to load: %s - error:", tile, tile.url, errorMsg );
+        $.console.log( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg );
         if( !tiledImage.debugMode ){
             tile.loading = false;
             tile.exists = false;

From c1d4652eee21dd7b9cba161df15d23a21a1df1ce Mon Sep 17 00:00:00 2001
From: Ian Gilman <ian@iangilman.com>
Date: Tue, 7 Jul 2015 09:52:03 -0700
Subject: [PATCH 14/16] Changelog for #679

---
 changelog.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/changelog.txt b/changelog.txt
index e42893fb..9c32e88d 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -10,6 +10,7 @@ OPENSEADRAGON CHANGELOG
 * Added additional coordinates conversion methods to TiledImage (#662)
 * 'display: none' no longer gets reset on overlays during draw (#668)
 * Added `preserveImageSizeOnResize` option (#666)
+* Better error reporting for tile load failures (#679)
 
 2.0.0:
 

From 57e6fdde900c08fc442e323e87d2117deba6cc6c Mon Sep 17 00:00:00 2001
From: Larissa Smith <smithl@familysearch.org>
Date: Tue, 7 Jul 2015 14:09:49 -0600
Subject: [PATCH 15/16] Added tests for collectionColumns use by world.arrange.

---
 test/modules/world.js | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/test/modules/world.js b/test/modules/world.js
index ce63f02a..0c5aebf7 100644
--- a/test/modules/world.js
+++ b/test/modules/world.js
@@ -213,6 +213,26 @@
 
             checkBounds(new OpenSeadragon.Rect(0, 0, 1, 4), 'one vertical column');
 
+            viewer.world.arrange({
+                layout: 'horizontal',
+                rows: false,
+                columns: 3,
+                tileSize: 1,
+                tileMargin: 0.5
+            });
+
+            checkBounds(new OpenSeadragon.Rect(0, 0, 4, 1), 'three horizontal columns (one horizontal row)');
+
+            viewer.world.arrange({
+                layout: 'vertical',
+                rows: false,
+                columns: 3,
+                tileSize: 1,
+                tileMargin: 0.5
+            });
+
+            checkBounds(new OpenSeadragon.Rect(0, 0, 1, 4), 'three vertical rows (one vertical column)');
+
             start();
         });
 

From 8508c2c4509177372026f1b0afbe002d179945af Mon Sep 17 00:00:00 2001
From: Ian Gilman <ian@iangilman.com>
Date: Wed, 8 Jul 2015 08:58:46 -0700
Subject: [PATCH 16/16] Changelog for #680

---
 changelog.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/changelog.txt b/changelog.txt
index 9c32e88d..8bb01788 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -11,6 +11,7 @@ OPENSEADRAGON CHANGELOG
 * 'display: none' no longer gets reset on overlays during draw (#668)
 * Added `preserveImageSizeOnResize` option (#666)
 * Better error reporting for tile load failures (#679)
+* Added collectionColumns as a configuration parameter (#680)
 
 2.0.0: